mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 04:53:28 +02:00
Merge branch 'master' into fix/Tofu-inArmored-Chat
This commit is contained in:
commit
c28424ebe8
125 changed files with 3456 additions and 1128 deletions
2
.github/workflows/master_build.yml
vendored
2
.github/workflows/master_build.yml
vendored
|
@ -248,7 +248,7 @@ jobs:
|
|||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_PATTERN }}
|
||||
path: ./build/${{ env.ARTIFACT_PATTERN }}
|
||||
path: ${{runner.workspace}}/build/${{ env.ARTIFACT_PATTERN }}
|
||||
if-no-files-found: error
|
||||
|
||||
#- name: Archive symbols
|
||||
|
|
142
CHANGELOG.md
142
CHANGELOG.md
|
@ -12,11 +12,147 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||
This project does **not** adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
<!-- ## [Unreleased] 2023.07.2 -->
|
||||
<!-- ## [2024.09.1] Unreleased -->
|
||||
|
||||
<!-- ## [2023.07.1] 2023.07.2 -->
|
||||
## [2024.07.1] 2023.07.12
|
||||
|
||||
### Fixes
|
||||
- Fix more warnings (PR1007)
|
||||
- Fix new debug build warning (PR1013)
|
||||
- Fix RPM packaging (PR1025)
|
||||
- Temporary fix for some script messages not being transmitted (PR1024)
|
||||
- Fix unhandled std::bad_weak_ptr (PR1037)
|
||||
- Fix long messages in Entity script log (PR1029)
|
||||
- Allow events from VR keyboard to overlay UI (PR1046)
|
||||
- Fix Fedora 40 server packages. (PR1057)
|
||||
- Fix crash in setCrashReporterEnabled (PR1065)
|
||||
- Fix mtoon issue on GLES (PR1055)
|
||||
- Fix GHA building hundreds of servers (PR1071)
|
||||
- Fix broken upload paths for RPM distributions. (PR1072)
|
||||
|
||||
### Changes
|
||||
- Text Entity Improvements (PR937)
|
||||
- GitHub Action Runner auto-scaling (PR1021)
|
||||
- Remove some external refrences (PR1026)
|
||||
- Update from deprecated actions/checkout and actions/upload-artifact (PR1023)
|
||||
- Update Ubuntu 20.04 amd64 Qt package (PR1032)
|
||||
- Cut back on master builds. (PR1049)
|
||||
- Increase default vertical FOV (PR1061)
|
||||
- Always enable crash reporting. (PR1064)
|
||||
- Update make-rpm-server to remove - characters. (PR1063)
|
||||
- Update VCPKG on Windows, so it can find newer versions of Visual Studio. (PR1073)
|
||||
|
||||
### Additions
|
||||
- Add a script to more easily build Debian and RPM server packages. (PR1011)
|
||||
- Add Fedora 40 servers (PR1010)
|
||||
- GitHub Actions server release builds (PR1022)
|
||||
- Wiggly lasers (PR1014)
|
||||
- Create Windows release builds. (PR1048)
|
||||
|
||||
### Removals
|
||||
- Remove broken ccache macro (PR1018)
|
||||
- Remove note about secure WebSockets not being supported. (PR1040)
|
||||
- Remove RELEASE_NAME (PR1039)
|
||||
- Remove hifiNeuron.dll (PR1075)
|
||||
- Remove remnants of RELEASE_NAME. (PR1077)
|
||||
|
||||
|
||||
## [2024.06.1] 2023.06.24
|
||||
|
||||
### Fixes
|
||||
- Fix QNetworkRequest::FollowRedirectsAttribute deprecated warning (PR711)
|
||||
- Fix luci (PR724)
|
||||
- Fix setting external port and IP address for manual networking modes (PR746)
|
||||
- particle billboarding is wrong in VR (PR747)
|
||||
- Upgrade openexr (PR752)
|
||||
- Fix OpenEXR on Windows (PR756)
|
||||
- Upgrade Steamworks and fix for ninja build (PR755)
|
||||
- Fixes for Oculus VR plugin (PR758)
|
||||
- Fix Ninja builds with Crashpad enabled on Windows (PR765)
|
||||
- Fix a bug in Entities.getEntityProperties (PR768)
|
||||
- Fixed returnNothingOnEmptyPropertyFlags (PR770)
|
||||
- ✨ "Update Existing Avatar" now properly updates the fst file (PR576)
|
||||
- Fix the doppleganger position in the tutorial (PR781)
|
||||
- Fix entity density not setting and not updating for motion states (PR819)
|
||||
- Add keyboard modifiers to entity pointer events (PR815)
|
||||
- 🐛 Fixed build on Windows (PR827)
|
||||
- Fix recording API documentation not being built (PR829)
|
||||
- Fix the display of Notifications (PR831)
|
||||
- Fix prebuild.py code ordering to make --get-vcpkg-id and --get-vcpkg-path correctly in the repo root (PR836)
|
||||
- Fixed avatar volume adjustment (PR841)
|
||||
- Respect cull face during shadow pass (PR820)
|
||||
- Fix Developer > UI > Show Overlays + Snap UI not hiding (PR823)
|
||||
- Fixed blendshapes in gltf importer (PR840)
|
||||
- Fix require behavior for modules (PR855)
|
||||
- 🐛 Fixed avatar bounding box being inverted (PR866)
|
||||
- Fix collisions on glTF avatars (PR867)
|
||||
- Clean up GeometryCache and remove _glColor4f (PR845)
|
||||
- Fix warnings as errors for MSVC (PR873)
|
||||
- Fix invalid animation reference in assignment client (PR854)
|
||||
- Fix previous commit for not loading textures on agent (PR893)
|
||||
- conversionPenaltyScore should accumulate (PR935)
|
||||
- Fix getEntityProperties for group properties + keylight direction (PR927)
|
||||
- Move helper script engines to their own threads (PR853)
|
||||
- Fix C++20 warnings (PR950)
|
||||
- Fix access check in getSkeletonModelURLFromScript (PR955)
|
||||
- SimplifiedUI adjustemnts (PR960)
|
||||
- Fixed locale problems with cgltf.h (PR978)
|
||||
- Fixed script signal proxy crashes (PR964)
|
||||
- Fixed deadlocks in Recording API (PR959)
|
||||
- Fix tests (PR991)
|
||||
- Add missing dependencymanager call, fixes test crash (PR994)
|
||||
- Skip packet capacity test when built in debug mode, as it triggers an assertion (PR993)
|
||||
- Fix some warnings (PR1003)
|
||||
- Fix Locker issue in RecordingScriptingInterface (PR1006)
|
||||
|
||||
### Changes
|
||||
- Update Linux vcpkg to the same as the Windows version (PR751)
|
||||
- Disable Oculus plugin on Visual Studio 2022 (PR754)
|
||||
- Reorganize startup to allow more control over plugins (PR716)
|
||||
- Script performance improvements (PR744)
|
||||
- Re-enable building Oculus plugin on VS 2022 (PR761)
|
||||
- Use response files on Ninja for long paths (PR764)
|
||||
- Improvement in controller scripts performance (PR766)
|
||||
- Update VCPKG for Linux aarch64 (PR807)
|
||||
- Linux server gha update (PR812)
|
||||
- glTF importer using cgltf library (PR835)
|
||||
- 🔧 Disable building electron screenshare app on windows (PR864)
|
||||
- Change the hash salt from Vircadia to Overte (PR869)
|
||||
- Change vircadia launcher dir (PR870)
|
||||
- Add Oculus to fullbody-enabled headsets list (PR882)
|
||||
- Add Ubuntu 24.04 to server packaging (PR966)
|
||||
- Improve network debugging messages to help with Conan PR (PR995)
|
||||
- Send OpenGL errors to log on debug builds (PR998)
|
||||
|
||||
### Additions
|
||||
- Add initial benchmarks for the script engine (PR710)
|
||||
- Add more ram Options (PR763)
|
||||
- Add VS22 cmake jumpstart script (PR773)
|
||||
- MToon materials (PR805)
|
||||
- Add a way to get VCPKG path and hash ID (PR813)
|
||||
- Entity script logging for script editor (PR673)
|
||||
- Create app: RenderWithZones Manager (PR806)
|
||||
- Added WebP support for binary glTF (PR860)
|
||||
- Support opaque (and black) particles (PR844)
|
||||
- Create App: Tools tab: CSS&HTML adjustments (PR880)
|
||||
- Create Application: Advanced Import functionality (PR877)
|
||||
- Create App.: "Copy Dimensions" and "Paste Dimensions" (PR863)
|
||||
- Create app: Entity List: "Copy ID" on menu and contextual menu. (PR865)
|
||||
- Add qByteArray to script value conversion (PR868)
|
||||
- Custom refresh rate profile (PR899)
|
||||
- support VRMC_materials_mtoon and KHR_materials_unlit (PR936)
|
||||
- Add very basic HTTP and HTTPS network tests (PR996)
|
||||
|
||||
### Removals
|
||||
- Disable Neuron by default (PR753)
|
||||
- Removing markdown from floof chat (PR769)
|
||||
- Remove debug print with URL from ModelLoader (PR837)
|
||||
- Remove legally problematic texture (PR851)
|
||||
|
||||
### Security
|
||||
- Added simple protection for avatar URL (PR887)
|
||||
- add canViewAssetURLs domain permissions (PR152)
|
||||
|
||||
<!-- ## [2023.06.1] 2023.06.12 -->
|
||||
|
||||
## [2023.11.1] 2023.11.24
|
||||
|
||||
|
|
|
@ -148,22 +148,22 @@ endif()
|
|||
|
||||
# OVERTE_WARNINGS
|
||||
#
|
||||
# Here we add the ability to whitelist warnings we've determined we can't fix, or are safe to
|
||||
# Here we add the ability to allowlist warnings we've determined we can't fix, or are safe to
|
||||
# ignore for one reason or another. The way of doing so is compiler-specific, so we deal with
|
||||
# the detection of that in cmake, and just pass it down to the code from here.
|
||||
#
|
||||
# We can also treat warnings as errors. Without the whitelist this will almost certainly lead
|
||||
# We can also treat warnings as errors. Without the allowlist this will almost certainly lead
|
||||
# to a build failure.
|
||||
|
||||
if(NOT DEFINED OVERTE_WARNINGS_WHITELIST)
|
||||
set(OVERTE_WARNINGS_WHITELIST true CACHE BOOL "Whitelist some warnings we can't currently fix")
|
||||
if(NOT DEFINED OVERTE_WARNINGS_ALLOWLIST)
|
||||
set(OVERTE_WARNINGS_ALLOWLIST true CACHE BOOL "Allowlist some warnings we can't currently fix")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED OVERTE_WARNINGS_AS_ERRORS)
|
||||
set(OVERTE_WARNINGS_AS_ERRORS false CACHE BOOL "Count warnings as errors")
|
||||
endif()
|
||||
|
||||
if(OVERTE_WARNINGS_WHITELIST)
|
||||
if(OVERTE_WARNINGS_ALLOWLIST)
|
||||
if (NOT WIN32)
|
||||
set(CMAKE_PLATFORM_INFO_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
include(CMakeDetermineCXXCompiler)
|
||||
|
@ -171,15 +171,15 @@ if(OVERTE_WARNINGS_WHITELIST)
|
|||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
message("GCC compiler detected, suppressing some unsolvable warnings.")
|
||||
add_compile_definitions(OVERTE_WARNINGS_WHITELIST_GCC)
|
||||
add_compile_definitions(OVERTE_WARNINGS_ALLOWLIST_GCC)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
message("Clang compiler detected, suppressing some unsolvable warnings.")
|
||||
add_compile_definitions(OVERTE_WARNINGS_WHITELIST_CLANG)
|
||||
add_compile_definitions(OVERTE_WARNINGS_ALLOWLIST_CLANG)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR (CMAKE_CXX_COMPILER_ID MATCHES "" AND WIN32))
|
||||
message("Microsoft Visual Studio compiler detected, suppressing some unsolvable warnings.")
|
||||
add_compile_definitions(OVERTE_WARNINGS_WHITELIST_MSVC)
|
||||
add_compile_definitions(OVERTE_WARNINGS_ALLOWLIST_MSVC)
|
||||
else()
|
||||
message("We don't know yet how to whitelist warnings for ${CMAKE_CXX_COMPILER_ID}")
|
||||
message("We don't know yet how to allowlist warnings for ${CMAKE_CXX_COMPILER_ID}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
Copyright (c) 2013-2019, High Fidelity, Inc.
|
||||
Copyright (c) 2019-2021, Vircadia contributors.
|
||||
Copyright (c) 2022-2023, Overte e.V.
|
||||
Copyright (c) 2022-2024, Overte e.V.
|
||||
All rights reserved.
|
||||
https://overte.org
|
||||
|
||||
|
|
|
@ -277,14 +277,14 @@ void AudioMixer::sendStatsPacket() {
|
|||
#ifdef DEBUG_EVENT_QUEUE
|
||||
QJsonObject qtStats;
|
||||
|
||||
_slavePool.queueStats(qtStats);
|
||||
_workerPool.queueStats(qtStats);
|
||||
statsObject["audio_thread_event_queue"] = qtStats;
|
||||
#endif
|
||||
|
||||
// general stats
|
||||
statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == DISABLE_STATIC_JITTER_FRAMES;
|
||||
|
||||
statsObject["threads"] = _slavePool.numThreads();
|
||||
statsObject["threads"] = _workerPool.numThreads();
|
||||
|
||||
statsObject["trailing_mix_ratio"] = _trailingMixRatio;
|
||||
statsObject["throttling_ratio"] = _throttlingRatio;
|
||||
|
@ -433,15 +433,15 @@ void AudioMixer::start() {
|
|||
|
||||
auto frameTimer = _frameTiming.timer();
|
||||
|
||||
// process (node-isolated) audio packets across slave threads
|
||||
// process (node-isolated) audio packets across worker threads
|
||||
{
|
||||
auto packetsTimer = _packetsTiming.timer();
|
||||
|
||||
// first clear the concurrent vector of added streams that the slaves will add to when they process packets
|
||||
// first clear the concurrent vector of added streams that the workers will add to when they process packets
|
||||
_workerSharedData.addedStreams.clear();
|
||||
|
||||
nodeList->nestedEach([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) {
|
||||
_slavePool.processPackets(cbegin, cend);
|
||||
_workerPool.processPackets(cbegin, cend);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -463,15 +463,15 @@ void AudioMixer::start() {
|
|||
numToRetain = nodeList->size() * (1.0f - _throttlingRatio);
|
||||
}
|
||||
nodeList->nestedEach([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) {
|
||||
// mix across slave threads
|
||||
// mix across worker threads
|
||||
auto mixTimer = _mixTiming.timer();
|
||||
_slavePool.mix(cbegin, cend, frame, numToRetain);
|
||||
_workerPool.mix(cbegin, cend, frame, numToRetain);
|
||||
});
|
||||
|
||||
// gather stats
|
||||
_slavePool.each([&](AudioMixerSlave& slave) {
|
||||
_stats.accumulate(slave.stats);
|
||||
slave.stats.reset();
|
||||
_workerPool.each([&](AudioMixerWorker& worker) {
|
||||
_stats.accumulate(worker.stats);
|
||||
worker.stats.reset();
|
||||
});
|
||||
|
||||
++frame;
|
||||
|
@ -573,7 +573,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
|
|||
const QString NUM_THREADS = "num_threads";
|
||||
int numThreads = audioThreadingGroupObject[NUM_THREADS].toString().toInt(&ok);
|
||||
if (ok) {
|
||||
_slavePool.setNumThreads(numThreads);
|
||||
_workerPool.setNumThreads(numThreads);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <plugins/Forward.h>
|
||||
|
||||
#include "AudioMixerStats.h"
|
||||
#include "AudioMixerSlavePool.h"
|
||||
#include "AudioMixerWorkerPool.h"
|
||||
|
||||
class PositionalAudioStream;
|
||||
class AvatarAudioStream;
|
||||
|
@ -107,7 +107,7 @@ private:
|
|||
int _numStatFrames { 0 };
|
||||
AudioMixerStats _stats;
|
||||
|
||||
AudioMixerSlavePool _slavePool { _workerSharedData };
|
||||
AudioMixerWorkerPool _workerPool { _workerSharedData };
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
|
@ -153,7 +153,7 @@ private:
|
|||
float _throttleStartTarget = 0.9f;
|
||||
float _throttleBackoffTarget = 0.44f;
|
||||
|
||||
AudioMixerSlave::SharedData _workerSharedData;
|
||||
AudioMixerWorker::SharedData _workerSharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixer_h
|
||||
|
|
|
@ -201,9 +201,9 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const
|
|||
float gain = unpackFloatGainFromByte(packedGain);
|
||||
|
||||
if (avatarUUID.isNull()) {
|
||||
// set the MASTER avatar gain
|
||||
setMasterAvatarGain(gain);
|
||||
qCDebug(audio) << "Setting MASTER avatar gain for" << uuid << "to" << gain;
|
||||
// set the PRIMARY avatar gain
|
||||
setPrimaryAvatarGain(gain);
|
||||
qCDebug(audio) << "Setting PRIMARY avatar gain for" << uuid << "to" << gain;
|
||||
} else {
|
||||
// set the per-source avatar gain
|
||||
setGainForAvatar(avatarUUID, gain);
|
||||
|
@ -218,8 +218,8 @@ void AudioMixerClientData::parseInjectorGainSet(ReceivedMessage& message, const
|
|||
message.readPrimitive(&packedGain);
|
||||
float gain = unpackFloatGainFromByte(packedGain);
|
||||
|
||||
setMasterInjectorGain(gain);
|
||||
qCDebug(audio) << "Setting MASTER injector gain for" << uuid << "to" << gain;
|
||||
setPrimaryInjectorGain(gain);
|
||||
qCDebug(audio) << "Setting PRIMARY injector gain for" << uuid << "to" << gain;
|
||||
}
|
||||
|
||||
bool setGainInStreams(const QUuid &nodeID, float gain, std::vector<AudioMixerClientData::MixableStream> &streamVector) {
|
||||
|
|
|
@ -86,10 +86,10 @@ public:
|
|||
// uses randomization to have the AudioMixer send a stats packet to this node around every second
|
||||
bool shouldSendStats(int frameNumber);
|
||||
|
||||
float getMasterAvatarGain() const { return _masterAvatarGain; }
|
||||
void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; }
|
||||
float getMasterInjectorGain() const { return _masterInjectorGain; }
|
||||
void setMasterInjectorGain(float gain) { _masterInjectorGain = gain; }
|
||||
float getPrimaryAvatarGain() const { return _primaryAvatarGain; }
|
||||
void setPrimaryAvatarGain(float gain) { _primaryAvatarGain = gain; }
|
||||
float getPrimaryInjectorGain() const { return _primaryInjectorGain; }
|
||||
void setPrimaryInjectorGain(float gain) { _primaryInjectorGain = gain; }
|
||||
|
||||
AudioLimiter audioLimiter;
|
||||
|
||||
|
@ -140,11 +140,11 @@ public:
|
|||
|
||||
Streams& getStreams() { return _streams; }
|
||||
|
||||
// thread-safe, called from AudioMixerSlave(s) while processing ignore packets for other nodes
|
||||
// thread-safe, called from AudioMixerWorker(s) while processing ignore packets for other nodes
|
||||
void ignoredByNode(QUuid nodeID);
|
||||
void unignoredByNode(QUuid nodeID);
|
||||
|
||||
// start of methods called non-concurrently from single AudioMixerSlave mixing for the owning node
|
||||
// start of methods called non-concurrently from single AudioMixerWorker mixing for the owning node
|
||||
|
||||
const Node::IgnoredNodeIDs& getNewIgnoredNodeIDs() const { return _newIgnoredNodeIDs; }
|
||||
const Node::IgnoredNodeIDs& getNewUnignoredNodeIDs() const { return _newUnignoredNodeIDs; }
|
||||
|
@ -163,7 +163,7 @@ public:
|
|||
bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; }
|
||||
void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; }
|
||||
|
||||
// end of methods called non-concurrently from single AudioMixerSlave
|
||||
// end of methods called non-concurrently from single AudioMixerWorker
|
||||
|
||||
signals:
|
||||
void injectorStreamFinished(const QUuid& streamID);
|
||||
|
@ -194,8 +194,8 @@ private:
|
|||
|
||||
int _frameToSendStats { 0 };
|
||||
|
||||
float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars
|
||||
float _masterInjectorGain { 1.0f }; // per-listener mixing gain, applied only to injectors
|
||||
float _primaryAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars
|
||||
float _primaryInjectorGain { 1.0f }; // per-listener mixing gain, applied only to injectors
|
||||
|
||||
CodecPluginPointer _codec;
|
||||
QString _selectedCodecName;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioMixerSlave.cpp
|
||||
// AudioMixerWorker.cpp
|
||||
// assignment-client/src/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 11/22/16.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioMixerSlave.h"
|
||||
#include "AudioMixerWorker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -50,12 +50,12 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData&
|
|||
|
||||
// mix helpers
|
||||
inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd);
|
||||
inline float computeGain(float masterAvatarGain, float masterInjectorGain, const AvatarAudioStream& listeningNodeStream,
|
||||
inline float computeGain(float primaryAvatarGain, float primaryInjectorGain, const AvatarAudioStream& listeningNodeStream,
|
||||
const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, float distance);
|
||||
inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd,
|
||||
const glm::vec3& relativePosition);
|
||||
|
||||
void AudioMixerSlave::processPackets(const SharedNodePointer& node) {
|
||||
void AudioMixerWorker::processPackets(const SharedNodePointer& node) {
|
||||
AudioMixerClientData* data = (AudioMixerClientData*)node->getLinkedData();
|
||||
if (data) {
|
||||
// process packets and collect the number of streams available for this frame
|
||||
|
@ -63,14 +63,14 @@ void AudioMixerSlave::processPackets(const SharedNodePointer& node) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioMixerSlave::configureMix(ConstIter begin, ConstIter end, unsigned int frame, int numToRetain) {
|
||||
void AudioMixerWorker::configureMix(ConstIter begin, ConstIter end, unsigned int frame, int numToRetain) {
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
_frame = frame;
|
||||
_numToRetain = numToRetain;
|
||||
}
|
||||
|
||||
void AudioMixerSlave::mix(const SharedNodePointer& node) {
|
||||
void AudioMixerWorker::mix(const SharedNodePointer& node) {
|
||||
// check that the node is valid
|
||||
AudioMixerClientData* data = (AudioMixerClientData*)node->getLinkedData();
|
||||
if (data == nullptr) {
|
||||
|
@ -178,7 +178,7 @@ private:
|
|||
};
|
||||
|
||||
|
||||
void AudioMixerSlave::addStreams(Node& listener, AudioMixerClientData& listenerData) {
|
||||
void AudioMixerWorker::addStreams(Node& listener, AudioMixerClientData& listenerData) {
|
||||
auto& ignoredNodeIDs = listener.getIgnoredNodeIDs();
|
||||
auto& ignoringNodeIDs = listenerData.getIgnoringNodeIDs();
|
||||
|
||||
|
@ -229,7 +229,7 @@ void AudioMixerSlave::addStreams(Node& listener, AudioMixerClientData& listenerD
|
|||
}
|
||||
}
|
||||
|
||||
bool shouldBeRemoved(const MixableStream& stream, const AudioMixerSlave::SharedData& sharedData) {
|
||||
bool shouldBeRemoved(const MixableStream& stream, const AudioMixerWorker::SharedData& sharedData) {
|
||||
return (contains(sharedData.removedNodes, stream.nodeStreamID.nodeLocalID) ||
|
||||
contains(sharedData.removedStreams, stream.nodeStreamID));
|
||||
};
|
||||
|
@ -306,7 +306,7 @@ float approximateVolume(const MixableStream& stream, const AvatarAudioStream* li
|
|||
return stream.positionalStream->getLastPopOutputTrailingLoudness() * gain;
|
||||
};
|
||||
|
||||
bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
||||
bool AudioMixerWorker::prepareMix(const SharedNodePointer& listener) {
|
||||
AvatarAudioStream* listenerAudioStream = static_cast<AudioMixerClientData*>(listener->getLinkedData())->getAvatarAudioStream();
|
||||
AudioMixerClientData* listenerData = static_cast<AudioMixerClientData*>(listener->getLinkedData());
|
||||
|
||||
|
@ -338,8 +338,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
}
|
||||
|
||||
if (!isThrottling) {
|
||||
updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(),
|
||||
listenerData->getMasterInjectorGain());
|
||||
updateHRTFParameters(stream, *listenerAudioStream, listenerData->getPrimaryAvatarGain(),
|
||||
listenerData->getPrimaryInjectorGain());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -363,8 +363,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
}
|
||||
|
||||
if (!isThrottling) {
|
||||
updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(),
|
||||
listenerData->getMasterInjectorGain());
|
||||
updateHRTFParameters(stream, *listenerAudioStream, listenerData->getPrimaryAvatarGain(),
|
||||
listenerData->getPrimaryInjectorGain());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -387,7 +387,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
return true;
|
||||
}
|
||||
|
||||
addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(),
|
||||
addStream(stream, *listenerAudioStream, listenerData->getPrimaryAvatarGain(), listenerData->getPrimaryInjectorGain(),
|
||||
isSoloing);
|
||||
|
||||
if (shouldBeInactive(stream)) {
|
||||
|
@ -423,7 +423,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
return true;
|
||||
}
|
||||
|
||||
addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(),
|
||||
addStream(stream, *listenerAudioStream, listenerData->getPrimaryAvatarGain(), listenerData->getPrimaryInjectorGain(),
|
||||
isSoloing);
|
||||
|
||||
if (shouldBeInactive(stream)) {
|
||||
|
@ -489,10 +489,10 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
return hasAudio;
|
||||
}
|
||||
|
||||
void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStream,
|
||||
void AudioMixerWorker::addStream(AudioMixerClientData::MixableStream& mixableStream,
|
||||
AvatarAudioStream& listeningNodeStream,
|
||||
float masterAvatarGain,
|
||||
float masterInjectorGain,
|
||||
float primaryAvatarGain,
|
||||
float primaryInjectorGain,
|
||||
bool isSoloing) {
|
||||
++stats.totalMixes;
|
||||
|
||||
|
@ -505,8 +505,8 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre
|
|||
|
||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||
float gain = isEcho ? 1.0f
|
||||
: (isSoloing ? masterAvatarGain
|
||||
: computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd,
|
||||
: (isSoloing ? primaryAvatarGain
|
||||
: computeGain(primaryAvatarGain, primaryInjectorGain, listeningNodeStream, *streamToAdd,
|
||||
relativePosition, distance));
|
||||
float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition);
|
||||
|
||||
|
@ -575,10 +575,10 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre
|
|||
}
|
||||
}
|
||||
|
||||
void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream,
|
||||
void AudioMixerWorker::updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream,
|
||||
AvatarAudioStream& listeningNodeStream,
|
||||
float masterAvatarGain,
|
||||
float masterInjectorGain) {
|
||||
float primaryAvatarGain,
|
||||
float primaryInjectorGain) {
|
||||
auto streamToAdd = mixableStream.positionalStream;
|
||||
|
||||
// check if this is a server echo of a source back to itself
|
||||
|
@ -587,7 +587,7 @@ void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream&
|
|||
glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream.getPosition();
|
||||
|
||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||
float gain = isEcho ? 1.0f : computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd,
|
||||
float gain = isEcho ? 1.0f : computeGain(primaryAvatarGain, primaryInjectorGain, listeningNodeStream, *streamToAdd,
|
||||
relativePosition, distance);
|
||||
float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition);
|
||||
|
||||
|
@ -596,7 +596,7 @@ void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream&
|
|||
++stats.hrtfUpdates;
|
||||
}
|
||||
|
||||
void AudioMixerSlave::resetHRTFState(AudioMixerClientData::MixableStream& mixableStream) {
|
||||
void AudioMixerWorker::resetHRTFState(AudioMixerClientData::MixableStream& mixableStream) {
|
||||
mixableStream.hrtf->reset();
|
||||
++stats.hrtfResets;
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi
|
|||
// injector: apply attenuation
|
||||
if (streamToAdd.getType() == PositionalAudioStream::Injector) {
|
||||
gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio();
|
||||
// injector: skip master gain
|
||||
// injector: skip primary gain
|
||||
}
|
||||
|
||||
// avatar: skip attenuation - it is too costly to approximate
|
||||
|
@ -723,11 +723,11 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi
|
|||
float distance = glm::length(relativePosition);
|
||||
return gain / distance;
|
||||
|
||||
// avatar: skip master gain
|
||||
// avatar: skip primary gain
|
||||
}
|
||||
|
||||
float computeGain(float masterAvatarGain,
|
||||
float masterInjectorGain,
|
||||
float computeGain(float primaryAvatarGain,
|
||||
float primaryInjectorGain,
|
||||
const AvatarAudioStream& listeningNodeStream,
|
||||
const PositionalAudioStream& streamToAdd,
|
||||
const glm::vec3& relativePosition,
|
||||
|
@ -737,8 +737,8 @@ float computeGain(float masterAvatarGain,
|
|||
// injector: apply attenuation
|
||||
if (streamToAdd.getType() == PositionalAudioStream::Injector) {
|
||||
gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio();
|
||||
// apply master gain
|
||||
gain *= masterInjectorGain;
|
||||
// apply primary gain
|
||||
gain *= primaryInjectorGain;
|
||||
|
||||
// avatar: apply fixed off-axis attenuation to make them quieter as they turn away
|
||||
} else if (streamToAdd.getType() == PositionalAudioStream::Microphone) {
|
||||
|
@ -754,8 +754,8 @@ float computeGain(float masterAvatarGain,
|
|||
|
||||
gain *= offAxisCoefficient;
|
||||
|
||||
// apply master gain
|
||||
gain *= masterAvatarGain;
|
||||
// apply primary gain
|
||||
gain *= primaryAvatarGain;
|
||||
}
|
||||
|
||||
auto& audioZones = AudioMixer::getAudioZones();
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioMixerSlave.h
|
||||
// AudioMixerWorker.h
|
||||
// assignment-client/src/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 11/22/16.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AudioMixerSlave_h
|
||||
#define hifi_AudioMixerSlave_h
|
||||
#ifndef hifi_AudioMixerWorker_h
|
||||
#define hifi_AudioMixerWorker_h
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
// Work around https://bugreports.qt.io/browse/QTBUG-80990
|
||||
|
@ -31,7 +31,7 @@
|
|||
class AvatarAudioStream;
|
||||
class AudioHRTF;
|
||||
|
||||
class AudioMixerSlave {
|
||||
class AudioMixerWorker {
|
||||
public:
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
|
||||
|
@ -41,7 +41,7 @@ public:
|
|||
std::vector<NodeIDStreamID> removedStreams;
|
||||
};
|
||||
|
||||
AudioMixerSlave(SharedData& sharedData) : _sharedData(sharedData) {};
|
||||
AudioMixerWorker(SharedData& sharedData) : _sharedData(sharedData) {};
|
||||
|
||||
// process packets for a given node (requires no configuration)
|
||||
void processPackets(const SharedNodePointer& node);
|
||||
|
@ -60,13 +60,13 @@ private:
|
|||
bool prepareMix(const SharedNodePointer& listener);
|
||||
void addStream(AudioMixerClientData::MixableStream& mixableStream,
|
||||
AvatarAudioStream& listeningNodeStream,
|
||||
float masterAvatarGain,
|
||||
float masterInjectorGain,
|
||||
float primaryAvatarGain,
|
||||
float primaryInjectorGain,
|
||||
bool isSoloing);
|
||||
void updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream,
|
||||
AvatarAudioStream& listeningNodeStream,
|
||||
float masterAvatarGain,
|
||||
float masterInjectorGain);
|
||||
float primaryAvatarGain,
|
||||
float primaryInjectorGain);
|
||||
void resetHRTFState(AudioMixerClientData::MixableStream& mixableStream);
|
||||
|
||||
void addStreams(Node& listener, AudioMixerClientData& listenerData);
|
||||
|
@ -84,4 +84,4 @@ private:
|
|||
SharedData& _sharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerSlave_h
|
||||
#endif // hifi_AudioMixerWorker_h
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioMixerSlavePool.cpp
|
||||
// AudioMixerWorkerPool.cpp
|
||||
// assignment-client/src/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 11/16/2016.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioMixerSlavePool.h"
|
||||
#include "AudioMixerWorkerPool.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
void AudioMixerSlaveThread::run() {
|
||||
void AudioMixerWorkerThread::run() {
|
||||
while (true) {
|
||||
wait();
|
||||
|
||||
|
@ -36,10 +36,10 @@ void AudioMixerSlaveThread::run() {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioMixerSlaveThread::wait() {
|
||||
void AudioMixerWorkerThread::wait() {
|
||||
{
|
||||
Lock lock(_pool._mutex);
|
||||
_pool._slaveCondition.wait(lock, [&] {
|
||||
_pool._workerCondition.wait(lock, [&] {
|
||||
assert(_pool._numStarted <= _pool._numThreads);
|
||||
return _pool._numStarted != _pool._numThreads;
|
||||
});
|
||||
|
@ -52,7 +52,7 @@ void AudioMixerSlaveThread::wait() {
|
|||
_function = _pool._function;
|
||||
}
|
||||
|
||||
void AudioMixerSlaveThread::notify(bool stopping) {
|
||||
void AudioMixerWorkerThread::notify(bool stopping) {
|
||||
{
|
||||
Lock lock(_pool._mutex);
|
||||
assert(_pool._numFinished < _pool._numThreads);
|
||||
|
@ -64,26 +64,26 @@ void AudioMixerSlaveThread::notify(bool stopping) {
|
|||
_pool._poolCondition.notify_one();
|
||||
}
|
||||
|
||||
bool AudioMixerSlaveThread::try_pop(SharedNodePointer& node) {
|
||||
bool AudioMixerWorkerThread::try_pop(SharedNodePointer& node) {
|
||||
return _pool._queue.try_pop(node);
|
||||
}
|
||||
|
||||
void AudioMixerSlavePool::processPackets(ConstIter begin, ConstIter end) {
|
||||
_function = &AudioMixerSlave::processPackets;
|
||||
_configure = [](AudioMixerSlave& slave) {};
|
||||
void AudioMixerWorkerPool::processPackets(ConstIter begin, ConstIter end) {
|
||||
_function = &AudioMixerWorker::processPackets;
|
||||
_configure = [](AudioMixerWorker& worker) {};
|
||||
run(begin, end);
|
||||
}
|
||||
|
||||
void AudioMixerSlavePool::mix(ConstIter begin, ConstIter end, unsigned int frame, int numToRetain) {
|
||||
_function = &AudioMixerSlave::mix;
|
||||
_configure = [=](AudioMixerSlave& slave) {
|
||||
slave.configureMix(_begin, _end, frame, numToRetain);
|
||||
void AudioMixerWorkerPool::mix(ConstIter begin, ConstIter end, unsigned int frame, int numToRetain) {
|
||||
_function = &AudioMixerWorker::mix;
|
||||
_configure = [=](AudioMixerWorker& worker) {
|
||||
worker.configureMix(_begin, _end, frame, numToRetain);
|
||||
};
|
||||
|
||||
run(begin, end);
|
||||
}
|
||||
|
||||
void AudioMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
||||
void AudioMixerWorkerPool::run(ConstIter begin, ConstIter end) {
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
|
||||
|
@ -97,7 +97,7 @@ void AudioMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
|
||||
// run
|
||||
_numStarted = _numFinished = 0;
|
||||
_slaveCondition.notify_all();
|
||||
_workerCondition.notify_all();
|
||||
|
||||
// wait
|
||||
_poolCondition.wait(lock, [&] {
|
||||
|
@ -111,17 +111,17 @@ void AudioMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
assert(_queue.empty());
|
||||
}
|
||||
|
||||
void AudioMixerSlavePool::each(std::function<void(AudioMixerSlave& slave)> functor) {
|
||||
for (auto& slave : _slaves) {
|
||||
functor(*slave.get());
|
||||
void AudioMixerWorkerPool::each(std::function<void(AudioMixerWorker& worker)> functor) {
|
||||
for (auto& worker : _workers) {
|
||||
functor(*worker.get());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
void AudioMixerSlavePool::queueStats(QJsonObject& stats) {
|
||||
void AudioMixerWorkerPool::queueStats(QJsonObject& stats) {
|
||||
unsigned i = 0;
|
||||
for (auto& slave : _slaves) {
|
||||
int queueSize = ::hifi::qt::getEventQueueSize(slave.get());
|
||||
for (auto& worker : _workers) {
|
||||
int queueSize = ::hifi::qt::getEventQueueSize(worker.get());
|
||||
QString queueName = QString("audio_thread_event_queue_%1").arg(i);
|
||||
stats[queueName] = queueSize;
|
||||
|
||||
|
@ -130,7 +130,7 @@ void AudioMixerSlavePool::queueStats(QJsonObject& stats) {
|
|||
}
|
||||
#endif // DEBUG_EVENT_QUEUE
|
||||
|
||||
void AudioMixerSlavePool::setNumThreads(int numThreads) {
|
||||
void AudioMixerWorkerPool::setNumThreads(int numThreads) {
|
||||
// clamp to allowed size
|
||||
{
|
||||
int maxThreads = QThread::idealThreadCount();
|
||||
|
@ -150,36 +150,36 @@ void AudioMixerSlavePool::setNumThreads(int numThreads) {
|
|||
resize(numThreads);
|
||||
}
|
||||
|
||||
void AudioMixerSlavePool::resize(int numThreads) {
|
||||
assert(_numThreads == (int)_slaves.size());
|
||||
void AudioMixerWorkerPool::resize(int numThreads) {
|
||||
assert(_numThreads == (int)_workers.size());
|
||||
|
||||
qDebug("%s: set %d threads (was %d)", __FUNCTION__, numThreads, _numThreads);
|
||||
|
||||
Lock lock(_mutex);
|
||||
|
||||
if (numThreads > _numThreads) {
|
||||
// start new slaves
|
||||
// start new workers
|
||||
for (int i = 0; i < numThreads - _numThreads; ++i) {
|
||||
auto slave = new AudioMixerSlaveThread(*this, _workerSharedData);
|
||||
QObject::connect(slave, &QThread::started, [] { setThreadName("AudioMixerSlaveThread"); });
|
||||
slave->start();
|
||||
_slaves.emplace_back(slave);
|
||||
auto worker = new AudioMixerWorkerThread(*this, _workerSharedData);
|
||||
QObject::connect(worker, &QThread::started, [] { setThreadName("AudioMixerWorkerThread"); });
|
||||
worker->start();
|
||||
_workers.emplace_back(worker);
|
||||
}
|
||||
} else if (numThreads < _numThreads) {
|
||||
auto extraBegin = _slaves.begin() + numThreads;
|
||||
auto extraBegin = _workers.begin() + numThreads;
|
||||
|
||||
// mark slaves to stop...
|
||||
auto slave = extraBegin;
|
||||
while (slave != _slaves.end()) {
|
||||
(*slave)->_stop = true;
|
||||
++slave;
|
||||
// mark workers to stop...
|
||||
auto worker = extraBegin;
|
||||
while (worker != _workers.end()) {
|
||||
(*worker)->_stop = true;
|
||||
++worker;
|
||||
}
|
||||
|
||||
// ...cycle them until they do stop...
|
||||
_numStopped = 0;
|
||||
while (_numStopped != (_numThreads - numThreads)) {
|
||||
_numStarted = _numFinished = _numStopped;
|
||||
_slaveCondition.notify_all();
|
||||
_workerCondition.notify_all();
|
||||
_poolCondition.wait(lock, [&] {
|
||||
assert(_numFinished <= _numThreads);
|
||||
return _numFinished == _numThreads;
|
||||
|
@ -187,18 +187,18 @@ void AudioMixerSlavePool::resize(int numThreads) {
|
|||
}
|
||||
|
||||
// ...wait for threads to finish...
|
||||
slave = extraBegin;
|
||||
while (slave != _slaves.end()) {
|
||||
QThread* thread = reinterpret_cast<QThread*>(slave->get());
|
||||
worker = extraBegin;
|
||||
while (worker != _workers.end()) {
|
||||
QThread* thread = reinterpret_cast<QThread*>(worker->get());
|
||||
static const int MAX_THREAD_WAIT_TIME = 10;
|
||||
thread->wait(MAX_THREAD_WAIT_TIME);
|
||||
++slave;
|
||||
++worker;
|
||||
}
|
||||
|
||||
// ...and erase them
|
||||
_slaves.erase(extraBegin, _slaves.end());
|
||||
_workers.erase(extraBegin, _workers.end());
|
||||
}
|
||||
|
||||
_numThreads = _numStarted = _numFinished = numThreads;
|
||||
assert(_numThreads == (int)_slaves.size());
|
||||
assert(_numThreads == (int)_workers.size());
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioMixerSlavePool.h
|
||||
// AudioMixerWorkerPool.h
|
||||
// assignment-client/src/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 11/16/2016.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AudioMixerSlavePool_h
|
||||
#define hifi_AudioMixerSlavePool_h
|
||||
#ifndef hifi_AudioMixerWorkerPool_h
|
||||
#define hifi_AudioMixerWorkerPool_h
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
@ -20,37 +20,37 @@
|
|||
#include <shared/QtHelpers.h>
|
||||
#include <TBBHelpers.h>
|
||||
|
||||
#include "AudioMixerSlave.h"
|
||||
#include "AudioMixerWorker.h"
|
||||
|
||||
class AudioMixerSlavePool;
|
||||
class AudioMixerWorkerPool;
|
||||
|
||||
class AudioMixerSlaveThread : public QThread, public AudioMixerSlave {
|
||||
class AudioMixerWorkerThread : public QThread, public AudioMixerWorker {
|
||||
Q_OBJECT
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
public:
|
||||
AudioMixerSlaveThread(AudioMixerSlavePool& pool, AudioMixerSlave::SharedData& sharedData)
|
||||
: AudioMixerSlave(sharedData), _pool(pool) {}
|
||||
AudioMixerWorkerThread(AudioMixerWorkerPool& pool, AudioMixerWorker::SharedData& sharedData)
|
||||
: AudioMixerWorker(sharedData), _pool(pool) {}
|
||||
|
||||
void run() override final;
|
||||
|
||||
private:
|
||||
friend class AudioMixerSlavePool;
|
||||
friend class AudioMixerWorkerPool;
|
||||
|
||||
void wait();
|
||||
void notify(bool stopping);
|
||||
bool try_pop(SharedNodePointer& node);
|
||||
|
||||
AudioMixerSlavePool& _pool;
|
||||
void (AudioMixerSlave::*_function)(const SharedNodePointer& node) { nullptr };
|
||||
AudioMixerWorkerPool& _pool;
|
||||
void (AudioMixerWorker::*_function)(const SharedNodePointer& node) { nullptr };
|
||||
bool _stop { false };
|
||||
};
|
||||
|
||||
// Slave pool for audio mixers
|
||||
// AudioMixerSlavePool is not thread-safe! It should be instantiated and used from a single thread.
|
||||
class AudioMixerSlavePool {
|
||||
// Worker pool for audio mixers
|
||||
// AudioMixerWorkerPool is not thread-safe! It should be instantiated and used from a single thread.
|
||||
class AudioMixerWorkerPool {
|
||||
using Queue = tbb::concurrent_queue<SharedNodePointer>;
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
@ -59,18 +59,18 @@ class AudioMixerSlavePool {
|
|||
public:
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
|
||||
AudioMixerSlavePool(AudioMixerSlave::SharedData& sharedData, int numThreads = QThread::idealThreadCount())
|
||||
AudioMixerWorkerPool(AudioMixerWorker::SharedData& sharedData, int numThreads = QThread::idealThreadCount())
|
||||
: _workerSharedData(sharedData) { setNumThreads(numThreads); }
|
||||
~AudioMixerSlavePool() { resize(0); }
|
||||
~AudioMixerWorkerPool() { resize(0); }
|
||||
|
||||
// process packets on slave threads
|
||||
// process packets on worker threads
|
||||
void processPackets(ConstIter begin, ConstIter end);
|
||||
|
||||
// mix on slave threads
|
||||
// mix on worker threads
|
||||
void mix(ConstIter begin, ConstIter end, unsigned int frame, int numToRetain);
|
||||
|
||||
// iterate over all slaves
|
||||
void each(std::function<void(AudioMixerSlave& slave)> functor);
|
||||
// iterate over all workers
|
||||
void each(std::function<void(AudioMixerWorker& worker)> functor);
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
void queueStats(QJsonObject& stats);
|
||||
|
@ -83,18 +83,18 @@ private:
|
|||
void run(ConstIter begin, ConstIter end);
|
||||
void resize(int numThreads);
|
||||
|
||||
std::vector<std::unique_ptr<AudioMixerSlaveThread>> _slaves;
|
||||
std::vector<std::unique_ptr<AudioMixerWorkerThread>> _workers;
|
||||
|
||||
friend void AudioMixerSlaveThread::wait();
|
||||
friend void AudioMixerSlaveThread::notify(bool stopping);
|
||||
friend bool AudioMixerSlaveThread::try_pop(SharedNodePointer& node);
|
||||
friend void AudioMixerWorkerThread::wait();
|
||||
friend void AudioMixerWorkerThread::notify(bool stopping);
|
||||
friend bool AudioMixerWorkerThread::try_pop(SharedNodePointer& node);
|
||||
|
||||
// synchronization state
|
||||
Mutex _mutex;
|
||||
ConditionVariable _slaveCondition;
|
||||
ConditionVariable _workerCondition;
|
||||
ConditionVariable _poolCondition;
|
||||
void (AudioMixerSlave::*_function)(const SharedNodePointer& node);
|
||||
std::function<void(AudioMixerSlave&)> _configure;
|
||||
void (AudioMixerWorker::*_function)(const SharedNodePointer& node);
|
||||
std::function<void(AudioMixerWorker&)> _configure;
|
||||
int _numThreads { 0 };
|
||||
int _numStarted { 0 }; // guarded by _mutex
|
||||
int _numFinished { 0 }; // guarded by _mutex
|
||||
|
@ -105,7 +105,7 @@ private:
|
|||
ConstIter _begin;
|
||||
ConstIter _end;
|
||||
|
||||
AudioMixerSlave::SharedData& _workerSharedData;
|
||||
AudioMixerWorker::SharedData& _workerSharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerSlavePool_h
|
||||
#endif // hifi_AudioMixerWorkerPool_h
|
|
@ -60,7 +60,7 @@ bool AvatarMixer::SessionDisplayName::operator<(const SessionDisplayName& rhs) c
|
|||
|
||||
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||
ThreadedAssignment(message),
|
||||
_slavePool(&_slaveSharedData)
|
||||
_workerPool(&_workerSharedData)
|
||||
{
|
||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||
DependencyManager::set<AssignmentDynamicFactory>();
|
||||
|
@ -297,7 +297,7 @@ void AvatarMixer::start() {
|
|||
auto end = usecTimestampNow();
|
||||
_processQueuedAvatarDataPacketsLockWaitElapsedTime += (end - start);
|
||||
|
||||
_slavePool.processIncomingPackets(cbegin, cend);
|
||||
_workerPool.processIncomingPackets(cbegin, cend);
|
||||
}, &lockWait, &nodeTransform, &functor);
|
||||
auto end = usecTimestampNow();
|
||||
_processQueuedAvatarDataPacketsElapsedTime += (end - start);
|
||||
|
@ -333,7 +333,7 @@ void AvatarMixer::start() {
|
|||
auto start = usecTimestampNow();
|
||||
nodeList->nestedEach([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) {
|
||||
auto start = usecTimestampNow();
|
||||
_slavePool.broadcastAvatarData(cbegin, cend, _lastFrameTimestamp, _maxKbpsPerNode, _throttlingRatio);
|
||||
_workerPool.broadcastAvatarData(cbegin, cend, _lastFrameTimestamp, _maxKbpsPerNode, _throttlingRatio);
|
||||
auto end = usecTimestampNow();
|
||||
_broadcastAvatarDataInner += (end - start);
|
||||
}, &lockWait, &nodeTransform, &functor);
|
||||
|
@ -761,14 +761,14 @@ void AvatarMixer::sendStatsPacket() {
|
|||
QJsonObject statsObject;
|
||||
|
||||
statsObject["broadcast_loop_rate"] = _loopRate.rate();
|
||||
statsObject["threads"] = _slavePool.numThreads();
|
||||
statsObject["threads"] = _workerPool.numThreads();
|
||||
statsObject["trailing_mix_ratio"] = _trailingMixRatio;
|
||||
statsObject["throttling_ratio"] = _throttlingRatio;
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
QJsonObject qtStats;
|
||||
|
||||
_slavePool.queueStats(qtStats);
|
||||
_workerPool.queueStats(qtStats);
|
||||
statsObject["avatar_thread_event_queue"] = qtStats;
|
||||
#endif
|
||||
|
||||
|
@ -821,41 +821,41 @@ void AvatarMixer::sendStatsPacket() {
|
|||
statsObject["parallelTasks"] = parallelTasks;
|
||||
|
||||
|
||||
AvatarMixerSlaveStats aggregateStats;
|
||||
AvatarMixerWorkerStats aggregateStats;
|
||||
|
||||
// gather stats
|
||||
_slavePool.each([&](AvatarMixerSlave& slave) {
|
||||
AvatarMixerSlaveStats stats;
|
||||
slave.harvestStats(stats);
|
||||
_workerPool.each([&](AvatarMixerWorker& worker) {
|
||||
AvatarMixerWorkerStats stats;
|
||||
worker.harvestStats(stats);
|
||||
aggregateStats += stats;
|
||||
});
|
||||
|
||||
QJsonObject slavesAggregatObject;
|
||||
QJsonObject workersAggregatObject;
|
||||
|
||||
slavesAggregatObject["received_1_nodesProcessed"] = TIGHT_LOOP_STAT(aggregateStats.nodesProcessed);
|
||||
workersAggregatObject["received_1_nodesProcessed"] = TIGHT_LOOP_STAT(aggregateStats.nodesProcessed);
|
||||
|
||||
slavesAggregatObject["sent_1_nodesBroadcastedTo"] = TIGHT_LOOP_STAT(aggregateStats.nodesBroadcastedTo);
|
||||
workersAggregatObject["sent_1_nodesBroadcastedTo"] = TIGHT_LOOP_STAT(aggregateStats.nodesBroadcastedTo);
|
||||
|
||||
float averageNodes = ((float)aggregateStats.nodesBroadcastedTo / (float)tightLoopFrames);
|
||||
|
||||
float averageOthersIncluded = averageNodes ? aggregateStats.numOthersIncluded / averageNodes : 0.0f;
|
||||
slavesAggregatObject["sent_2_averageOthersIncluded"] = TIGHT_LOOP_STAT(averageOthersIncluded);
|
||||
workersAggregatObject["sent_2_averageOthersIncluded"] = TIGHT_LOOP_STAT(averageOthersIncluded);
|
||||
|
||||
float averageOverBudgetAvatars = averageNodes ? aggregateStats.overBudgetAvatars / averageNodes : 0.0f;
|
||||
slavesAggregatObject["sent_3_averageOverBudgetAvatars"] = TIGHT_LOOP_STAT(averageOverBudgetAvatars);
|
||||
slavesAggregatObject["sent_4_averageDataBytes"] = TIGHT_LOOP_STAT(aggregateStats.numDataBytesSent);
|
||||
slavesAggregatObject["sent_5_averageTraitsBytes"] = TIGHT_LOOP_STAT(aggregateStats.numTraitsBytesSent);
|
||||
slavesAggregatObject["sent_6_averageIdentityBytes"] = TIGHT_LOOP_STAT(aggregateStats.numIdentityBytesSent);
|
||||
slavesAggregatObject["sent_7_averageHeroAvatars"] = TIGHT_LOOP_STAT(aggregateStats.numHeroesIncluded);
|
||||
workersAggregatObject["sent_3_averageOverBudgetAvatars"] = TIGHT_LOOP_STAT(averageOverBudgetAvatars);
|
||||
workersAggregatObject["sent_4_averageDataBytes"] = TIGHT_LOOP_STAT(aggregateStats.numDataBytesSent);
|
||||
workersAggregatObject["sent_5_averageTraitsBytes"] = TIGHT_LOOP_STAT(aggregateStats.numTraitsBytesSent);
|
||||
workersAggregatObject["sent_6_averageIdentityBytes"] = TIGHT_LOOP_STAT(aggregateStats.numIdentityBytesSent);
|
||||
workersAggregatObject["sent_7_averageHeroAvatars"] = TIGHT_LOOP_STAT(aggregateStats.numHeroesIncluded);
|
||||
|
||||
slavesAggregatObject["timing_1_processIncomingPackets"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.processIncomingPacketsElapsedTime);
|
||||
slavesAggregatObject["timing_2_ignoreCalculation"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.ignoreCalculationElapsedTime);
|
||||
slavesAggregatObject["timing_3_toByteArray"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.toByteArrayElapsedTime);
|
||||
slavesAggregatObject["timing_4_avatarDataPacking"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.avatarDataPackingElapsedTime);
|
||||
slavesAggregatObject["timing_5_packetSending"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.packetSendingElapsedTime);
|
||||
slavesAggregatObject["timing_6_jobElapsedTime"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.jobElapsedTime);
|
||||
workersAggregatObject["timing_1_processIncomingPackets"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.processIncomingPacketsElapsedTime);
|
||||
workersAggregatObject["timing_2_ignoreCalculation"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.ignoreCalculationElapsedTime);
|
||||
workersAggregatObject["timing_3_toByteArray"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.toByteArrayElapsedTime);
|
||||
workersAggregatObject["timing_4_avatarDataPacking"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.avatarDataPackingElapsedTime);
|
||||
workersAggregatObject["timing_5_packetSending"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.packetSendingElapsedTime);
|
||||
workersAggregatObject["timing_6_jobElapsedTime"] = TIGHT_LOOP_STAT_UINT64(aggregateStats.jobElapsedTime);
|
||||
|
||||
statsObject["slaves_aggregate (per frame)"] = slavesAggregatObject;
|
||||
statsObject["workers_aggregate (per frame)"] = workersAggregatObject;
|
||||
|
||||
_handleViewFrustumPacketElapsedTime = 0;
|
||||
_handleAvatarIdentityPacketElapsedTime = 0;
|
||||
|
@ -1016,9 +1016,9 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
|||
numThreads = 1;
|
||||
}
|
||||
qCDebug(avatars) << "Avatar mixer will use specified number of threads:" << numThreads;
|
||||
_slavePool.setNumThreads(numThreads);
|
||||
_workerPool.setNumThreads(numThreads);
|
||||
} else {
|
||||
qCDebug(avatars) << "Avatar mixer will automatically determine number of threads to use. Using:" << _slavePool.numThreads() << "threads.";
|
||||
qCDebug(avatars) << "Avatar mixer will automatically determine number of threads to use. Using:" << _workerPool.numThreads() << "threads.";
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1035,7 +1035,7 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
|||
static const QString PRIORITY_FRACTION_KEY = "priority_fraction";
|
||||
if (avatarMixerGroupObject.contains(PRIORITY_FRACTION_KEY)) {
|
||||
float priorityFraction = float(avatarMixerGroupObject[PRIORITY_FRACTION_KEY].toDouble());
|
||||
_slavePool.setPriorityReservedFraction(std::min(std::max(0.0f, priorityFraction), 1.0f));
|
||||
_workerPool.setPriorityReservedFraction(std::min(std::max(0.0f, priorityFraction), 1.0f));
|
||||
qCDebug(avatars) << "Avatar mixer reserving" << priorityFraction << "of bandwidth for priority avatars";
|
||||
}
|
||||
}
|
||||
|
@ -1058,23 +1058,23 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
|||
qCDebug(avatars) << "This domain requires a minimum avatar height of" << _domainMinimumHeight
|
||||
<< "and a maximum avatar height of" << _domainMaximumHeight;
|
||||
|
||||
static const QString AVATAR_WHITELIST_OPTION = "avatar_whitelist";
|
||||
_slaveSharedData.skeletonURLWhitelist = avatarMixerGroupObject[AVATAR_WHITELIST_OPTION]
|
||||
static const QString AVATAR_ALLOWLIST_OPTION = "avatar_allowlist";
|
||||
_workerSharedData.skeletonURLAllowlist = avatarMixerGroupObject[AVATAR_ALLOWLIST_OPTION]
|
||||
.toString().split(',', Qt::KeepEmptyParts);
|
||||
|
||||
static const QString REPLACEMENT_AVATAR_OPTION = "replacement_avatar";
|
||||
_slaveSharedData.skeletonReplacementURL = avatarMixerGroupObject[REPLACEMENT_AVATAR_OPTION]
|
||||
_workerSharedData.skeletonReplacementURL = avatarMixerGroupObject[REPLACEMENT_AVATAR_OPTION]
|
||||
.toString();
|
||||
|
||||
if (_slaveSharedData.skeletonURLWhitelist.count() == 1 && _slaveSharedData.skeletonURLWhitelist[0].isEmpty()) {
|
||||
if (_workerSharedData.skeletonURLAllowlist.count() == 1 && _workerSharedData.skeletonURLAllowlist[0].isEmpty()) {
|
||||
// KeepEmptyParts above will parse "," as ["", ""] (which is ok), but "" as [""] (which is not ok).
|
||||
_slaveSharedData.skeletonURLWhitelist.clear();
|
||||
_workerSharedData.skeletonURLAllowlist.clear();
|
||||
}
|
||||
|
||||
if (_slaveSharedData.skeletonURLWhitelist.isEmpty()) {
|
||||
if (_workerSharedData.skeletonURLAllowlist.isEmpty()) {
|
||||
qCDebug(avatars) << "All avatars are allowed.";
|
||||
} else {
|
||||
qCDebug(avatars) << "Avatars other than" << _slaveSharedData.skeletonURLWhitelist << "will be replaced by" << (_slaveSharedData.skeletonReplacementURL.isEmpty() ? "default" : _slaveSharedData.skeletonReplacementURL.toString());
|
||||
qCDebug(avatars) << "Avatars other than" << _workerSharedData.skeletonURLAllowlist << "will be replaced by" << (_workerSharedData.skeletonReplacementURL.isEmpty() ? "default" : _workerSharedData.skeletonReplacementURL.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1099,7 @@ void AvatarMixer::setupEntityQuery() {
|
|||
priorityZoneQuery["name"] = true; // Handy for debugging.
|
||||
|
||||
_entityViewer.getOctreeQuery().setJSONParameters(priorityZoneQuery);
|
||||
_slaveSharedData.entityTree = entityTree;
|
||||
_workerSharedData.entityTree = entityTree;
|
||||
}
|
||||
|
||||
void AvatarMixer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "../entities/EntityTreeHeadlessViewer.h"
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
#include "AvatarMixerSlavePool.h"
|
||||
#include "AvatarMixerWorkerPool.h"
|
||||
|
||||
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
||||
class AvatarMixer : public ThreadedAssignment {
|
||||
|
@ -153,8 +153,8 @@ private:
|
|||
|
||||
RateCounter<> _loopRate; // this is the rate that the main thread tight loop runs
|
||||
|
||||
AvatarMixerSlavePool _slavePool;
|
||||
SlaveSharedData _slaveSharedData;
|
||||
AvatarMixerWorkerPool _workerPool;
|
||||
WorkerSharedData _workerSharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarMixer_h
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "AvatarLogging.h"
|
||||
|
||||
#include "AvatarMixerSlave.h"
|
||||
#include "AvatarMixerWorker.h"
|
||||
|
||||
AvatarMixerClientData::AvatarMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID) : NodeData(nodeID, nodeLocalID) {
|
||||
// in case somebody calls getSessionUUID on the AvatarData instance, make sure it has the right ID
|
||||
|
@ -52,7 +52,7 @@ void AvatarMixerClientData::queuePacket(QSharedPointer<ReceivedMessage> message,
|
|||
_packetQueue.push(message);
|
||||
}
|
||||
|
||||
int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData) {
|
||||
int AvatarMixerClientData::processPackets(const WorkerSharedData& workerSharedData) {
|
||||
int packetsProcessed = 0;
|
||||
SharedNodePointer node = _packetQueue.node;
|
||||
assert(_packetQueue.empty() || node);
|
||||
|
@ -65,10 +65,10 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData
|
|||
|
||||
switch (packet->getType()) {
|
||||
case PacketType::AvatarData:
|
||||
parseData(*packet, slaveSharedData);
|
||||
parseData(*packet, workerSharedData);
|
||||
break;
|
||||
case PacketType::SetAvatarTraits:
|
||||
processSetTraitsMessage(*packet, slaveSharedData, *node);
|
||||
processSetTraitsMessage(*packet, workerSharedData, *node);
|
||||
break;
|
||||
case PacketType::BulkAvatarTraitsAck:
|
||||
processBulkAvatarTraitsAckMessage(*packet);
|
||||
|
@ -127,7 +127,7 @@ struct FindContainingZone {
|
|||
|
||||
} // namespace
|
||||
|
||||
int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveSharedData& slaveSharedData) {
|
||||
int AvatarMixerClientData::parseData(ReceivedMessage& message, const WorkerSharedData& workerSharedData) {
|
||||
// pull the sequence number from the data first
|
||||
uint16_t sequenceNumber;
|
||||
|
||||
|
@ -150,7 +150,7 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveShared
|
|||
|
||||
auto newPosition = _avatar->getClientGlobalPosition();
|
||||
if (newPosition != oldPosition || _avatar->getNeedsHeroCheck()) {
|
||||
EntityTree& entityTree = *slaveSharedData.entityTree;
|
||||
EntityTree& entityTree = *workerSharedData.entityTree;
|
||||
FindContainingZone findContainingZone{ newPosition };
|
||||
entityTree.recurseTreeWithOperation(&FindContainingZone::operation, &findContainingZone);
|
||||
bool currentlyHasPriority = findContainingZone.isInPriorityZone;
|
||||
|
@ -176,7 +176,7 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveShared
|
|||
}
|
||||
|
||||
void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||
const SlaveSharedData& slaveSharedData,
|
||||
const WorkerSharedData& workerSharedData,
|
||||
Node& sendingNode) {
|
||||
// Trying to read more bytes than available, bail
|
||||
if (message.getBytesLeftToRead() < qint64(sizeof(AvatarTraits::TraitVersion))) {
|
||||
|
@ -221,8 +221,8 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
|||
_avatar->processTrait(traitType, message.read(traitSize));
|
||||
_lastReceivedTraitVersions[traitType] = packetTraitVersion;
|
||||
if (traitType == AvatarTraits::SkeletonModelURL) {
|
||||
// special handling for skeleton model URL, since we need to make sure it is in the whitelist
|
||||
checkSkeletonURLAgainstWhitelist(slaveSharedData, sendingNode, packetTraitVersion);
|
||||
// special handling for skeleton model URL, since we need to make sure it is in the allowlist
|
||||
checkSkeletonURLAgainstAllowlist(workerSharedData, sendingNode, packetTraitVersion);
|
||||
}
|
||||
|
||||
anyTraitsChanged = true;
|
||||
|
@ -366,36 +366,36 @@ void AvatarMixerClientData::processBulkAvatarTraitsAckMessage(ReceivedMessage& m
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData,
|
||||
void AvatarMixerClientData::checkSkeletonURLAgainstAllowlist(const WorkerSharedData& workerSharedData,
|
||||
Node& sendingNode,
|
||||
AvatarTraits::TraitVersion traitVersion) {
|
||||
const auto& whitelist = slaveSharedData.skeletonURLWhitelist;
|
||||
const auto& allowlist = workerSharedData.skeletonURLAllowlist;
|
||||
|
||||
if (!whitelist.isEmpty()) {
|
||||
bool inWhitelist = false;
|
||||
if (!allowlist.isEmpty()) {
|
||||
bool inAllowlist = false;
|
||||
auto avatarURL = _avatar->getSkeletonModelURL();
|
||||
|
||||
// The avatar is in the whitelist if:
|
||||
// 1. The avatar's URL's host matches one of the hosts of the URLs in the whitelist AND
|
||||
// 2. The avatar's URL's path starts with the path of that same URL in the whitelist
|
||||
for (const auto& whiteListedPrefix : whitelist) {
|
||||
auto whiteListURL = QUrl::fromUserInput(whiteListedPrefix);
|
||||
// check if this script URL matches the whitelist domain and, optionally, is beneath the path
|
||||
if (avatarURL.host().compare(whiteListURL.host(), Qt::CaseInsensitive) == 0 &&
|
||||
avatarURL.path().startsWith(whiteListURL.path(), Qt::CaseInsensitive)) {
|
||||
inWhitelist = true;
|
||||
// The avatar is in the allowlist if:
|
||||
// 1. The avatar's URL's host matches one of the hosts of the URLs in the allowlist AND
|
||||
// 2. The avatar's URL's path starts with the path of that same URL in the allowlist
|
||||
for (const auto& allowListedPrefix : allowlist) {
|
||||
auto allowListURL = QUrl::fromUserInput(allowListedPrefix);
|
||||
// check if this script URL matches the allowlist domain and, optionally, is beneath the path
|
||||
if (avatarURL.host().compare(allowListURL.host(), Qt::CaseInsensitive) == 0 &&
|
||||
avatarURL.path().startsWith(allowListURL.path(), Qt::CaseInsensitive)) {
|
||||
inAllowlist = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inWhitelist) {
|
||||
if (!inAllowlist) {
|
||||
// make sure we're not unecessarily overriding the default avatar with the default avatar
|
||||
if (_avatar->getWireSafeSkeletonModelURL() != slaveSharedData.skeletonReplacementURL) {
|
||||
if (_avatar->getWireSafeSkeletonModelURL() != workerSharedData.skeletonReplacementURL) {
|
||||
// we need to change this avatar's skeleton URL, and send them a traits packet informing them of the change
|
||||
qDebug() << "Overwriting avatar URL" << _avatar->getWireSafeSkeletonModelURL() << "to replacement"
|
||||
<< slaveSharedData.skeletonReplacementURL << "for" << sendingNode.getUUID();
|
||||
_avatar->setSkeletonModelURL(slaveSharedData.skeletonReplacementURL);
|
||||
<< workerSharedData.skeletonReplacementURL << "for" << sendingNode.getUUID();
|
||||
_avatar->setSkeletonModelURL(workerSharedData.skeletonReplacementURL);
|
||||
|
||||
auto packet = NLPacket::create(PacketType::SetAvatarTraits, -1, true);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps";
|
|||
const QString OUTBOUND_AVATAR_TRAITS_STATS_KEY = "outbound_av_traits_kbps";
|
||||
const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
|
||||
|
||||
struct SlaveSharedData;
|
||||
struct WorkerSharedData;
|
||||
|
||||
class AvatarMixerClientData : public NodeData {
|
||||
Q_OBJECT
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
using PerNodeTraitVersions = std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions>;
|
||||
|
||||
using NodeData::parseData; // Avoid clang warning about hiding.
|
||||
int parseData(ReceivedMessage& message, const SlaveSharedData& SlaveSharedData);
|
||||
int parseData(ReceivedMessage& message, const WorkerSharedData& WorkerSharedData);
|
||||
MixerAvatar& getAvatar() { return *_avatar; }
|
||||
const MixerAvatar& getAvatar() const { return *_avatar; }
|
||||
const MixerAvatar* getConstAvatarData() const { return _avatar.get(); }
|
||||
|
@ -130,12 +130,12 @@ public:
|
|||
QVector<JointData>& getLastOtherAvatarSentJoints(NLPacket::LocalID otherAvatar) { return _lastOtherAvatarSentJoints[otherAvatar]; }
|
||||
|
||||
void queuePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node);
|
||||
int processPackets(const SlaveSharedData& slaveSharedData); // returns number of packets processed
|
||||
int processPackets(const WorkerSharedData& workerSharedData); // returns number of packets processed
|
||||
|
||||
void processSetTraitsMessage(ReceivedMessage& message, const SlaveSharedData& slaveSharedData, Node& sendingNode);
|
||||
void processSetTraitsMessage(ReceivedMessage& message, const WorkerSharedData& workerSharedData, Node& sendingNode);
|
||||
void emulateDeleteEntitiesTraitsMessage(const QList<QUuid>& avatarEntityIDs);
|
||||
void processBulkAvatarTraitsAckMessage(ReceivedMessage& message);
|
||||
void checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData, Node& sendingNode,
|
||||
void checkSkeletonURLAgainstAllowlist(const WorkerSharedData& workerSharedData, Node& sendingNode,
|
||||
AvatarTraits::TraitVersion traitVersion);
|
||||
|
||||
using TraitsCheckTimestamp = std::chrono::steady_clock::time_point;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AvatarMixerSlave.cpp
|
||||
// AvatarMixerWorker.cpp
|
||||
// assignment-client/src/avatar
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/14/2017.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AvatarMixerSlave.h"
|
||||
#include "AvatarMixerWorker.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
@ -36,12 +36,12 @@
|
|||
|
||||
namespace chrono = std::chrono;
|
||||
|
||||
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
||||
void AvatarMixerWorker::configure(ConstIter begin, ConstIter end) {
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
}
|
||||
|
||||
void AvatarMixerSlave::configureBroadcast(ConstIter begin, ConstIter end,
|
||||
void AvatarMixerWorker::configureBroadcast(ConstIter begin, ConstIter end,
|
||||
p_high_resolution_clock::time_point lastFrameTimestamp,
|
||||
float maxKbpsPerNode, float throttlingRatio,
|
||||
float priorityReservedFraction) {
|
||||
|
@ -53,13 +53,13 @@ void AvatarMixerSlave::configureBroadcast(ConstIter begin, ConstIter end,
|
|||
_avatarHeroFraction = priorityReservedFraction;
|
||||
}
|
||||
|
||||
void AvatarMixerSlave::harvestStats(AvatarMixerSlaveStats& stats) {
|
||||
void AvatarMixerWorker::harvestStats(AvatarMixerWorkerStats& stats) {
|
||||
stats = _stats;
|
||||
_stats.reset();
|
||||
}
|
||||
|
||||
|
||||
void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) {
|
||||
void AvatarMixerWorker::processIncomingPackets(const SharedNodePointer& node) {
|
||||
auto start = usecTimestampNow();
|
||||
auto nodeData = dynamic_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
|
@ -70,7 +70,7 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) {
|
|||
_stats.processIncomingPacketsElapsedTime += (end - start);
|
||||
}
|
||||
|
||||
int AvatarMixerSlave::sendIdentityPacket(NLPacketList& packetList, const AvatarMixerClientData* nodeData, const Node& destinationNode) {
|
||||
int AvatarMixerWorker::sendIdentityPacket(NLPacketList& packetList, const AvatarMixerClientData* nodeData, const Node& destinationNode) {
|
||||
if (destinationNode.getType() == NodeType::Agent && !destinationNode.isUpstream()) {
|
||||
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
|
||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
||||
|
@ -83,7 +83,7 @@ int AvatarMixerSlave::sendIdentityPacket(NLPacketList& packetList, const AvatarM
|
|||
}
|
||||
}
|
||||
|
||||
qint64 AvatarMixerSlave::addTraitsNodeHeader(AvatarMixerClientData* listeningNodeData,
|
||||
qint64 AvatarMixerWorker::addTraitsNodeHeader(AvatarMixerClientData* listeningNodeData,
|
||||
const AvatarMixerClientData* sendingNodeData,
|
||||
NLPacketList& traitsPacketList,
|
||||
qint64 bytesWritten) {
|
||||
|
@ -98,7 +98,7 @@ qint64 AvatarMixerSlave::addTraitsNodeHeader(AvatarMixerClientData* listeningNod
|
|||
return bytesWritten;
|
||||
}
|
||||
|
||||
qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
||||
qint64 AvatarMixerWorker::addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
||||
const AvatarMixerClientData* sendingNodeData,
|
||||
NLPacketList& traitsPacketList) {
|
||||
|
||||
|
@ -245,7 +245,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
|||
return bytesWritten;
|
||||
}
|
||||
|
||||
int AvatarMixerSlave::sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode) {
|
||||
int AvatarMixerWorker::sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode) {
|
||||
if (AvatarMixer::shouldReplicateTo(agentNode, destinationNode)) {
|
||||
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(true);
|
||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
||||
|
@ -262,7 +262,7 @@ int AvatarMixerSlave::sendReplicatedIdentityPacket(const Node& agentNode, const
|
|||
|
||||
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||
void AvatarMixerWorker::broadcastAvatarData(const SharedNodePointer& node) {
|
||||
quint64 start = usecTimestampNow();
|
||||
|
||||
if ((node->getType() == NodeType::Agent || node->getType() == NodeType::EntityScriptServer) && node->getLinkedData() && node->getActiveSocket() && !node->isUpstream()) {
|
||||
|
@ -311,7 +311,7 @@ namespace {
|
|||
|
||||
} // Close anonymous namespace.
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||
void AvatarMixerWorker::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||
const Node* destinationNode = node.data();
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -680,7 +680,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
|
||||
uint64_t REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US = 5 * 1000 * 1000;
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node) {
|
||||
void AvatarMixerWorker::broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node) {
|
||||
_stats.downstreamMixersBroadcastedTo++;
|
||||
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AvatarMixerSlave.h
|
||||
// AvatarMixerWorker.h
|
||||
// assignment-client/src/avatar
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/14/2017.
|
||||
|
@ -9,14 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AvatarMixerSlave_h
|
||||
#define hifi_AvatarMixerSlave_h
|
||||
#ifndef hifi_AvatarMixerWorker_h
|
||||
#define hifi_AvatarMixerWorker_h
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
class AvatarMixerClientData;
|
||||
|
||||
class AvatarMixerSlaveStats {
|
||||
class AvatarMixerWorkerStats {
|
||||
public:
|
||||
int nodesProcessed { 0 };
|
||||
int packetsProcessed { 0 };
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
jobElapsedTime = 0;
|
||||
}
|
||||
|
||||
AvatarMixerSlaveStats& operator+=(const AvatarMixerSlaveStats& rhs) {
|
||||
AvatarMixerWorkerStats& operator+=(const AvatarMixerWorkerStats& rhs) {
|
||||
nodesProcessed += rhs.nodesProcessed;
|
||||
packetsProcessed += rhs.packetsProcessed;
|
||||
processIncomingPacketsElapsedTime += rhs.processIncomingPacketsElapsedTime;
|
||||
|
@ -96,15 +96,15 @@ public:
|
|||
class EntityTree;
|
||||
using EntityTreePointer = std::shared_ptr<EntityTree>;
|
||||
|
||||
struct SlaveSharedData {
|
||||
QStringList skeletonURLWhitelist;
|
||||
struct WorkerSharedData {
|
||||
QStringList skeletonURLAllowlist;
|
||||
QUrl skeletonReplacementURL;
|
||||
EntityTreePointer entityTree;
|
||||
};
|
||||
|
||||
class AvatarMixerSlave {
|
||||
class AvatarMixerWorker {
|
||||
public:
|
||||
AvatarMixerSlave(SlaveSharedData* sharedData) : _sharedData(sharedData) {};
|
||||
AvatarMixerWorker(WorkerSharedData* sharedData) : _sharedData(sharedData) {};
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
|
||||
void configure(ConstIter begin, ConstIter end);
|
||||
|
@ -116,7 +116,7 @@ public:
|
|||
void processIncomingPackets(const SharedNodePointer& node);
|
||||
void broadcastAvatarData(const SharedNodePointer& node);
|
||||
|
||||
void harvestStats(AvatarMixerSlaveStats& stats);
|
||||
void harvestStats(AvatarMixerWorkerStats& stats);
|
||||
|
||||
private:
|
||||
int sendIdentityPacket(NLPacketList& packet, const AvatarMixerClientData* nodeData, const Node& destinationNode);
|
||||
|
@ -143,8 +143,8 @@ private:
|
|||
float _throttlingRatio { 0.0f };
|
||||
float _avatarHeroFraction { 0.4f };
|
||||
|
||||
AvatarMixerSlaveStats _stats;
|
||||
SlaveSharedData* _sharedData;
|
||||
AvatarMixerWorkerStats _stats;
|
||||
WorkerSharedData* _sharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarMixerSlave_h
|
||||
#endif // hifi_AvatarMixerWorker_h
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AvatarMixerSlavePool.cpp
|
||||
// AvatarMixerWorkerPool.cpp
|
||||
// assignment-client/src/avatar
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/14/2017.
|
||||
|
@ -9,12 +9,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AvatarMixerSlavePool.h"
|
||||
#include "AvatarMixerWorkerPool.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
void AvatarMixerSlaveThread::run() {
|
||||
void AvatarMixerWorkerThread::run() {
|
||||
while (true) {
|
||||
wait();
|
||||
|
||||
|
@ -32,10 +32,10 @@ void AvatarMixerSlaveThread::run() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixerSlaveThread::wait() {
|
||||
void AvatarMixerWorkerThread::wait() {
|
||||
{
|
||||
Lock lock(_pool._mutex);
|
||||
_pool._slaveCondition.wait(lock, [&] {
|
||||
_pool._workerCondition.wait(lock, [&] {
|
||||
assert(_pool._numStarted <= _pool._numThreads);
|
||||
return _pool._numStarted != _pool._numThreads;
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ void AvatarMixerSlaveThread::wait() {
|
|||
_function = _pool._function;
|
||||
}
|
||||
|
||||
void AvatarMixerSlaveThread::notify(bool stopping) {
|
||||
void AvatarMixerWorkerThread::notify(bool stopping) {
|
||||
{
|
||||
Lock lock(_pool._mutex);
|
||||
assert(_pool._numFinished < _pool._numThreads);
|
||||
|
@ -59,30 +59,30 @@ void AvatarMixerSlaveThread::notify(bool stopping) {
|
|||
_pool._poolCondition.notify_one();
|
||||
}
|
||||
|
||||
bool AvatarMixerSlaveThread::try_pop(SharedNodePointer& node) {
|
||||
bool AvatarMixerWorkerThread::try_pop(SharedNodePointer& node) {
|
||||
return _pool._queue.try_pop(node);
|
||||
}
|
||||
|
||||
void AvatarMixerSlavePool::processIncomingPackets(ConstIter begin, ConstIter end) {
|
||||
_function = &AvatarMixerSlave::processIncomingPackets;
|
||||
_configure = [=](AvatarMixerSlave& slave) {
|
||||
slave.configure(begin, end);
|
||||
void AvatarMixerWorkerPool::processIncomingPackets(ConstIter begin, ConstIter end) {
|
||||
_function = &AvatarMixerWorker::processIncomingPackets;
|
||||
_configure = [=](AvatarMixerWorker& worker) {
|
||||
worker.configure(begin, end);
|
||||
};
|
||||
run(begin, end);
|
||||
}
|
||||
|
||||
void AvatarMixerSlavePool::broadcastAvatarData(ConstIter begin, ConstIter end,
|
||||
void AvatarMixerWorkerPool::broadcastAvatarData(ConstIter begin, ConstIter end,
|
||||
p_high_resolution_clock::time_point lastFrameTimestamp,
|
||||
float maxKbpsPerNode, float throttlingRatio) {
|
||||
_function = &AvatarMixerSlave::broadcastAvatarData;
|
||||
_configure = [=](AvatarMixerSlave& slave) {
|
||||
slave.configureBroadcast(begin, end, lastFrameTimestamp, maxKbpsPerNode, throttlingRatio,
|
||||
_function = &AvatarMixerWorker::broadcastAvatarData;
|
||||
_configure = [=](AvatarMixerWorker& worker) {
|
||||
worker.configureBroadcast(begin, end, lastFrameTimestamp, maxKbpsPerNode, throttlingRatio,
|
||||
_priorityReservedFraction);
|
||||
};
|
||||
run(begin, end);
|
||||
}
|
||||
|
||||
void AvatarMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
||||
void AvatarMixerWorkerPool::run(ConstIter begin, ConstIter end) {
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
|
||||
|
@ -96,7 +96,7 @@ void AvatarMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
|
||||
// run
|
||||
_numStarted = _numFinished = 0;
|
||||
_slaveCondition.notify_all();
|
||||
_workerCondition.notify_all();
|
||||
|
||||
// wait
|
||||
_poolCondition.wait(lock, [&] {
|
||||
|
@ -111,17 +111,17 @@ void AvatarMixerSlavePool::run(ConstIter begin, ConstIter end) {
|
|||
}
|
||||
|
||||
|
||||
void AvatarMixerSlavePool::each(std::function<void(AvatarMixerSlave& slave)> functor) {
|
||||
for (auto& slave : _slaves) {
|
||||
functor(*slave.get());
|
||||
void AvatarMixerWorkerPool::each(std::function<void(AvatarMixerWorker& worker)> functor) {
|
||||
for (auto& worker : _workers) {
|
||||
functor(*worker.get());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
void AvatarMixerSlavePool::queueStats(QJsonObject& stats) {
|
||||
void AvatarMixerWorkerPool::queueStats(QJsonObject& stats) {
|
||||
unsigned i = 0;
|
||||
for (auto& slave : _slaves) {
|
||||
int queueSize = ::hifi::qt::getEventQueueSize(slave.get());
|
||||
for (auto& worker : _workers) {
|
||||
int queueSize = ::hifi::qt::getEventQueueSize(worker.get());
|
||||
QString queueName = QString("avatar_thread_event_queue_%1").arg(i);
|
||||
stats[queueName] = queueSize;
|
||||
|
||||
|
@ -130,7 +130,7 @@ void AvatarMixerSlavePool::queueStats(QJsonObject& stats) {
|
|||
}
|
||||
#endif // DEBUG_EVENT_QUEUE
|
||||
|
||||
void AvatarMixerSlavePool::setNumThreads(int numThreads) {
|
||||
void AvatarMixerWorkerPool::setNumThreads(int numThreads) {
|
||||
// clamp to allowed size
|
||||
{
|
||||
int maxThreads = QThread::idealThreadCount();
|
||||
|
@ -150,35 +150,35 @@ void AvatarMixerSlavePool::setNumThreads(int numThreads) {
|
|||
resize(numThreads);
|
||||
}
|
||||
|
||||
void AvatarMixerSlavePool::resize(int numThreads) {
|
||||
assert(_numThreads == (int)_slaves.size());
|
||||
void AvatarMixerWorkerPool::resize(int numThreads) {
|
||||
assert(_numThreads == (int)_workers.size());
|
||||
|
||||
qDebug("%s: set %d threads (was %d)", __FUNCTION__, numThreads, _numThreads);
|
||||
|
||||
Lock lock(_mutex);
|
||||
|
||||
if (numThreads > _numThreads) {
|
||||
// start new slaves
|
||||
// start new workers
|
||||
for (int i = 0; i < numThreads - _numThreads; ++i) {
|
||||
auto slave = new AvatarMixerSlaveThread(*this, _slaveSharedData);
|
||||
slave->start();
|
||||
_slaves.emplace_back(slave);
|
||||
auto worker = new AvatarMixerWorkerThread(*this, _workerSharedData);
|
||||
worker->start();
|
||||
_workers.emplace_back(worker);
|
||||
}
|
||||
} else if (numThreads < _numThreads) {
|
||||
auto extraBegin = _slaves.begin() + numThreads;
|
||||
auto extraBegin = _workers.begin() + numThreads;
|
||||
|
||||
// mark slaves to stop...
|
||||
auto slave = extraBegin;
|
||||
while (slave != _slaves.end()) {
|
||||
(*slave)->_stop = true;
|
||||
++slave;
|
||||
// mark workers to stop...
|
||||
auto worker = extraBegin;
|
||||
while (worker != _workers.end()) {
|
||||
(*worker)->_stop = true;
|
||||
++worker;
|
||||
}
|
||||
|
||||
// ...cycle them until they do stop...
|
||||
_numStopped = 0;
|
||||
while (_numStopped != (_numThreads - numThreads)) {
|
||||
_numStarted = _numFinished = _numStopped;
|
||||
_slaveCondition.notify_all();
|
||||
_workerCondition.notify_all();
|
||||
_poolCondition.wait(lock, [&] {
|
||||
assert(_numFinished <= _numThreads);
|
||||
return _numFinished == _numThreads;
|
||||
|
@ -186,18 +186,18 @@ void AvatarMixerSlavePool::resize(int numThreads) {
|
|||
}
|
||||
|
||||
// ...wait for threads to finish...
|
||||
slave = extraBegin;
|
||||
while (slave != _slaves.end()) {
|
||||
QThread* thread = reinterpret_cast<QThread*>(slave->get());
|
||||
worker = extraBegin;
|
||||
while (worker != _workers.end()) {
|
||||
QThread* thread = reinterpret_cast<QThread*>(worker->get());
|
||||
static const int MAX_THREAD_WAIT_TIME = 10;
|
||||
thread->wait(MAX_THREAD_WAIT_TIME);
|
||||
++slave;
|
||||
++worker;
|
||||
}
|
||||
|
||||
// ...and erase them
|
||||
_slaves.erase(extraBegin, _slaves.end());
|
||||
_workers.erase(extraBegin, _workers.end());
|
||||
}
|
||||
|
||||
_numThreads = _numStarted = _numFinished = numThreads;
|
||||
assert(_numThreads == (int)_slaves.size());
|
||||
assert(_numThreads == (int)_workers.size());
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AvatarMixerSlavePool.h
|
||||
// AvatarMixerWorkerPool.h
|
||||
// assignment-client/src/avatar
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/14/2017.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AvatarMixerSlavePool_h
|
||||
#define hifi_AvatarMixerSlavePool_h
|
||||
#ifndef hifi_AvatarMixerWorkerPool_h
|
||||
#define hifi_AvatarMixerWorkerPool_h
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
@ -22,38 +22,38 @@
|
|||
#include <NodeList.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
|
||||
#include "AvatarMixerSlave.h"
|
||||
#include "AvatarMixerWorker.h"
|
||||
|
||||
|
||||
class AvatarMixerSlavePool;
|
||||
class AvatarMixerWorkerPool;
|
||||
|
||||
class AvatarMixerSlaveThread : public QThread, public AvatarMixerSlave {
|
||||
class AvatarMixerWorkerThread : public QThread, public AvatarMixerWorker {
|
||||
Q_OBJECT
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
public:
|
||||
AvatarMixerSlaveThread(AvatarMixerSlavePool& pool, SlaveSharedData* slaveSharedData) :
|
||||
AvatarMixerSlave(slaveSharedData), _pool(pool) {};
|
||||
AvatarMixerWorkerThread(AvatarMixerWorkerPool& pool, WorkerSharedData* workerSharedData) :
|
||||
AvatarMixerWorker(workerSharedData), _pool(pool) {};
|
||||
|
||||
void run() override final;
|
||||
|
||||
private:
|
||||
friend class AvatarMixerSlavePool;
|
||||
friend class AvatarMixerWorkerPool;
|
||||
|
||||
void wait();
|
||||
void notify(bool stopping);
|
||||
bool try_pop(SharedNodePointer& node);
|
||||
|
||||
AvatarMixerSlavePool& _pool;
|
||||
void (AvatarMixerSlave::*_function)(const SharedNodePointer& node) { nullptr };
|
||||
AvatarMixerWorkerPool& _pool;
|
||||
void (AvatarMixerWorker::*_function)(const SharedNodePointer& node) { nullptr };
|
||||
bool _stop { false };
|
||||
};
|
||||
|
||||
// Slave pool for avatar mixers
|
||||
// AvatarMixerSlavePool is not thread-safe! It should be instantiated and used from a single thread.
|
||||
class AvatarMixerSlavePool {
|
||||
// Worker pool for avatar mixers
|
||||
// AvatarMixerWorkerPool is not thread-safe! It should be instantiated and used from a single thread.
|
||||
class AvatarMixerWorkerPool {
|
||||
using Queue = tbb::concurrent_queue<SharedNodePointer>;
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
@ -62,17 +62,17 @@ class AvatarMixerSlavePool {
|
|||
public:
|
||||
using ConstIter = NodeList::const_iterator;
|
||||
|
||||
AvatarMixerSlavePool(SlaveSharedData* slaveSharedData, int numThreads = QThread::idealThreadCount()) :
|
||||
_slaveSharedData(slaveSharedData) { setNumThreads(numThreads); }
|
||||
~AvatarMixerSlavePool() { resize(0); }
|
||||
AvatarMixerWorkerPool(WorkerSharedData* workerSharedData, int numThreads = QThread::idealThreadCount()) :
|
||||
_workerSharedData(workerSharedData) { setNumThreads(numThreads); }
|
||||
~AvatarMixerWorkerPool() { resize(0); }
|
||||
|
||||
// Jobs the slave pool can do...
|
||||
// Jobs the worker pool can do...
|
||||
void processIncomingPackets(ConstIter begin, ConstIter end);
|
||||
void broadcastAvatarData(ConstIter begin, ConstIter end,
|
||||
p_high_resolution_clock::time_point lastFrameTimestamp, float maxKbpsPerNode, float throttlingRatio);
|
||||
|
||||
// iterate over all slaves
|
||||
void each(std::function<void(AvatarMixerSlave& slave)> functor);
|
||||
// iterate over all workers
|
||||
void each(std::function<void(AvatarMixerWorker& worker)> functor);
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
void queueStats(QJsonObject& stats);
|
||||
|
@ -88,18 +88,18 @@ private:
|
|||
void run(ConstIter begin, ConstIter end);
|
||||
void resize(int numThreads);
|
||||
|
||||
std::vector<std::unique_ptr<AvatarMixerSlaveThread>> _slaves;
|
||||
std::vector<std::unique_ptr<AvatarMixerWorkerThread>> _workers;
|
||||
|
||||
friend void AvatarMixerSlaveThread::wait();
|
||||
friend void AvatarMixerSlaveThread::notify(bool stopping);
|
||||
friend bool AvatarMixerSlaveThread::try_pop(SharedNodePointer& node);
|
||||
friend void AvatarMixerWorkerThread::wait();
|
||||
friend void AvatarMixerWorkerThread::notify(bool stopping);
|
||||
friend bool AvatarMixerWorkerThread::try_pop(SharedNodePointer& node);
|
||||
|
||||
// synchronization state
|
||||
Mutex _mutex;
|
||||
ConditionVariable _slaveCondition;
|
||||
ConditionVariable _workerCondition;
|
||||
ConditionVariable _poolCondition;
|
||||
void (AvatarMixerSlave::*_function)(const SharedNodePointer& node);
|
||||
std::function<void(AvatarMixerSlave&)> _configure;
|
||||
void (AvatarMixerWorker::*_function)(const SharedNodePointer& node);
|
||||
std::function<void(AvatarMixerWorker&)> _configure;
|
||||
|
||||
// Set from Domain Settings:
|
||||
float _priorityReservedFraction { 0.4f };
|
||||
|
@ -114,7 +114,7 @@ private:
|
|||
ConstIter _begin;
|
||||
ConstIter _end;
|
||||
|
||||
SlaveSharedData* _slaveSharedData;
|
||||
WorkerSharedData* _workerSharedData;
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarMixerSlavePool_h
|
||||
#endif // hifi_AvatarMixerWorkerPool_h
|
|
@ -320,11 +320,11 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio
|
|||
tree->setWantEditLogging(wantEditLogging);
|
||||
tree->setWantTerseEditLogging(wantTerseEditLogging);
|
||||
|
||||
QString entityScriptSourceWhitelist;
|
||||
if (readOptionString("entityScriptSourceWhitelist", settingsSectionObject, entityScriptSourceWhitelist)) {
|
||||
tree->setEntityScriptSourceWhitelist(entityScriptSourceWhitelist);
|
||||
QString entityScriptSourceAllowlist;
|
||||
if (readOptionString("entityScriptSourceAllowlist", settingsSectionObject, entityScriptSourceAllowlist)) {
|
||||
tree->setEntityScriptSourceAllowlist(entityScriptSourceAllowlist);
|
||||
} else {
|
||||
tree->setEntityScriptSourceWhitelist("");
|
||||
tree->setEntityScriptSourceAllowlist("");
|
||||
}
|
||||
|
||||
auto entityEditFilters = DependencyManager::get<EntityEditFilters>();
|
||||
|
|
|
@ -26,7 +26,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set_from_env(STABLE_BUILD STABLE_BUILD 0)
|
||||
|
||||
set_from_env(PRELOADED_STARTUP_LOCATION PRELOADED_STARTUP_LOCATION "")
|
||||
set_from_env(PRELOADED_SCRIPT_WHITELIST PRELOADED_SCRIPT_WHITELIST "")
|
||||
set_from_env(PRELOADED_SCRIPT_ALLOWLIST PRELOADED_SCRIPT_ALLOWLIST "")
|
||||
|
||||
set_from_env(BYPASS_SIGNING BYPASS_SIGNING 0)
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace BuildInfo {
|
|||
const QString BUILD_GLOBAL_SERVICES = "@BUILD_GLOBAL_SERVICES@";
|
||||
const QString BUILD_TIME = "@BUILD_TIME@";
|
||||
const QString PRELOADED_STARTUP_LOCATION = "@PRELOADED_STARTUP_LOCATION@";
|
||||
const QString PRELOADED_SCRIPT_WHITELIST = "@PRELOADED_SCRIPT_WHITELIST@";
|
||||
const QString PRELOADED_SCRIPT_ALLOWLIST = "@PRELOADED_SCRIPT_ALLOWLIST@";
|
||||
|
||||
enum BuildType {
|
||||
Dev,
|
||||
|
|
|
@ -178,7 +178,7 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
}
|
||||
|
||||
// If this user is a known member of a domain group, give them the implied permissions.
|
||||
// Do before processing verifiedUsername in case user is logged into the Directory Services and is a member of a blacklist group.
|
||||
// Do before processing verifiedUsername in case user is logged into the Directory Services and is a member of a blocklist group.
|
||||
if (!verifiedDomainUserName.isEmpty()) {
|
||||
auto userGroups = _domainGroupMemberships[verifiedDomainUserName];
|
||||
foreach (QString userGroup, userGroups) {
|
||||
|
@ -277,8 +277,8 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
}
|
||||
}
|
||||
|
||||
// if this user is a known member of a blacklist group, remove the implied permissions
|
||||
foreach (QUuid groupID, _server->_settingsManager.getBlacklistGroupIDs()) {
|
||||
// if this user is a known member of a blocklist group, remove the implied permissions
|
||||
foreach (QUuid groupID, _server->_settingsManager.getBlocklistGroupIDs()) {
|
||||
QUuid rankID = _server->_settingsManager.isGroupMember(verifiedUsername, groupID);
|
||||
if (rankID != QUuid()) {
|
||||
QUuid rankID = _server->_settingsManager.isGroupMember(verifiedUsername, groupID);
|
||||
|
@ -287,7 +287,7 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
|
||||
GroupRank rank = _server->_settingsManager.getGroupRank(groupID, rankID);
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "| user-permissions: user is in blacklist group:" << groupID << " rank:" << rank.name
|
||||
qDebug() << "| user-permissions: user is in blocklist group:" << groupID << " rank:" << rank.name
|
||||
<< "so:" << userPerms;
|
||||
#endif
|
||||
}
|
||||
|
@ -299,20 +299,20 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
userPerms.setVerifiedUserName(verifiedUsername);
|
||||
}
|
||||
|
||||
// If this user is a known member of an domain group that is blacklisted, remove the implied permissions.
|
||||
// If this user is a known member of an domain group that is blocklisted, remove the implied permissions.
|
||||
if (!verifiedDomainUserName.isEmpty()) {
|
||||
auto userGroups = _domainGroupMemberships[verifiedDomainUserName];
|
||||
foreach(QString userGroup, userGroups) {
|
||||
// A domain group is signified by a leading special character, "@".
|
||||
// Multiple domain groups may be specified in one domain server setting as a comma- and/or space-separated lists of
|
||||
// domain group names. For example, "@silver @Gold, @platinum".
|
||||
auto domainGroups = _server->_settingsManager.getDomainServerBlacklistGroupNames()
|
||||
auto domainGroups = _server->_settingsManager.getDomainServerBlocklistGroupNames()
|
||||
.filter(QRegularExpression("^(.*[\\s,])?" + QRegularExpression::escape(userGroup) + "([\\s,].*)?$",
|
||||
QRegularExpression::CaseInsensitiveOption));
|
||||
foreach(QString domainGroup, domainGroups) {
|
||||
userPerms &= ~_server->_settingsManager.getForbiddensForGroup(domainGroup, QUuid());
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "| user-permissions: domain user is in blacklist group:" << domainGroup << "so:" << userPerms;
|
||||
qDebug() << "| user-permissions: domain user is in blocklist group:" << domainGroup << "so:" << userPerms;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1027,7 +1027,7 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
|||
|
||||
QJsonObject json;
|
||||
QSet<QString> groupIDSet;
|
||||
foreach (QUuid groupID, _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlacklistGroupIDs()) {
|
||||
foreach (QUuid groupID, _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlocklistGroupIDs()) {
|
||||
groupIDSet += groupID.toString().mid(1,36);
|
||||
}
|
||||
|
||||
|
|
|
@ -341,17 +341,17 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions, [this] { _metadata->securityChanged(true); });
|
||||
|
||||
qDebug() << "domain-server is running";
|
||||
static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist";
|
||||
static const QString AC_SUBNET_ALLOWLIST_SETTING_PATH = "security.ac_subnet_allowlist";
|
||||
|
||||
static const Subnet LOCALHOST { QHostAddress("127.0.0.1"), 32 };
|
||||
_acSubnetWhitelist = { LOCALHOST };
|
||||
_acSubnetAllowlist = { LOCALHOST };
|
||||
|
||||
auto whitelist = _settingsManager.valueOrDefaultValueForKeyPath(AC_SUBNET_WHITELIST_SETTING_PATH).toStringList();
|
||||
for (auto& subnet : whitelist) {
|
||||
auto allowlist = _settingsManager.valueOrDefaultValueForKeyPath(AC_SUBNET_ALLOWLIST_SETTING_PATH).toStringList();
|
||||
for (auto& subnet : allowlist) {
|
||||
auto netmaskParts = subnet.trimmed().split("/");
|
||||
|
||||
if (netmaskParts.size() > 2) {
|
||||
qDebug() << "Ignoring subnet in whitelist, malformed: " << subnet;
|
||||
qDebug() << "Ignoring subnet in allowlist, malformed: " << subnet;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
bool ok;
|
||||
netmask = netmaskParts[1].toInt(&ok);
|
||||
if (!ok) {
|
||||
qDebug() << "Ignoring subnet in whitelist, bad netmask: " << subnet;
|
||||
qDebug() << "Ignoring subnet in allowlist, bad netmask: " << subnet;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -371,10 +371,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
auto ip = QHostAddress(netmaskParts[0]);
|
||||
|
||||
if (!ip.isNull()) {
|
||||
qDebug() << "Adding AC whitelist subnet: " << subnet << " -> " << (ip.toString() + "/" + QString::number(netmask));
|
||||
_acSubnetWhitelist.push_back({ ip , netmask });
|
||||
qDebug() << "Adding AC allowlist subnet: " << subnet << " -> " << (ip.toString() + "/" + QString::number(netmask));
|
||||
_acSubnetAllowlist.push_back({ ip , netmask });
|
||||
} else {
|
||||
qDebug() << "Ignoring subnet in whitelist, invalid ip portion: " << subnet;
|
||||
qDebug() << "Ignoring subnet in allowlist, invalid ip portion: " << subnet;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1502,8 +1502,8 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer<ReceivedMessage
|
|||
return senderAddr.isInSubnet(mask);
|
||||
};
|
||||
|
||||
auto it = find_if(_acSubnetWhitelist.begin(), _acSubnetWhitelist.end(), isHostAddressInSubnet);
|
||||
if (it == _acSubnetWhitelist.end()) {
|
||||
auto it = find_if(_acSubnetAllowlist.begin(), _acSubnetAllowlist.end(), isHostAddressInSubnet);
|
||||
if (it == _acSubnetAllowlist.end()) {
|
||||
HIFI_FDEBUG("Received an assignment connect request from a disallowed ip address:"
|
||||
<< senderAddr.toString());
|
||||
return;
|
||||
|
|
|
@ -251,7 +251,7 @@ private:
|
|||
|
||||
QString operationToString(const QNetworkAccessManager::Operation &op);
|
||||
|
||||
SubnetList _acSubnetWhitelist;
|
||||
SubnetList _acSubnetAllowlist;
|
||||
|
||||
std::vector<QString> _replicatedUsernames;
|
||||
|
||||
|
|
|
@ -172,20 +172,20 @@ static const QMap<QString, DomainServerExporter::MetricType> TYPE_MAP {
|
|||
{ "avatar_mixer_single_core_tasks_process_events" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_single_core_tasks_queue_incoming_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_send_stats" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_received_1_nodes_processed" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_1_nodes_broadcasted_to" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_2_average_others_included" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_3_average_over_budget_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_4_average_data_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_5_average_traits_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_6_average_identity_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_7_average_hero_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_1_process_incoming_packets" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_2_ignore_calculation" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_3_to_byte_array" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_4_avatar_data_packing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_5_packet_sending" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_6_job_elapsed_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_received_1_nodes_processed" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_1_nodes_broadcasted_to" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_2_average_others_included" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_3_average_over_budget_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_4_average_data_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_5_average_traits_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_6_average_identity_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_sent_7_average_hero_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_1_process_incoming_packets" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_2_ignore_calculation" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_3_to_byte_array" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_4_avatar_data_packing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_5_packet_sending" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_workers_aggregate_per_frame_timing_6_job_elapsed_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_threads" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_throttling_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_trailing_mix_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
|
@ -254,9 +254,9 @@ static const QMap<QString, DomainServerExporter::MetricType> TYPE_MAP {
|
|||
//
|
||||
// For numeric values with an unit, instead of trying to parse it, the stats will just need to
|
||||
// have a second copy of the metric added, with the value expressed as a number, with the original
|
||||
// being blacklisted here.
|
||||
// being blocklisted here.
|
||||
|
||||
static const QSet<QString> BLACKLIST = {
|
||||
static const QSet<QString> BLOCKLIST = {
|
||||
"asset_server_connection_stats_last_heard", // Timestamp as a string
|
||||
"asset_server_username", // Username
|
||||
"audio_mixer_listeners_jitter_downstream_avg_gap", // Number as string with unit name, alternative added
|
||||
|
@ -379,7 +379,7 @@ void DomainServerExporter::generateMetricsFromJson(QTextStream& stream,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (BLACKLIST.contains(metricName)) {
|
||||
if (BLOCKLIST.contains(metricName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -688,7 +688,7 @@ void DomainServerSettingsManager::packPermissions() {
|
|||
// save settings for groups
|
||||
packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH);
|
||||
|
||||
// save settings for blacklist groups
|
||||
// save settings for blocklist groups
|
||||
packPermissionsForMap("permissions", _groupForbiddens, GROUP_FORBIDDENS_KEYPATH);
|
||||
|
||||
persistToFile();
|
||||
|
@ -869,7 +869,7 @@ bool DomainServerSettingsManager::ensurePermissionsForGroupRanks() {
|
|||
}
|
||||
}
|
||||
|
||||
QList<QUuid> forbiddenGroupIDs = getBlacklistGroupIDs();
|
||||
QList<QUuid> forbiddenGroupIDs = getBlocklistGroupIDs();
|
||||
foreach (QUuid groupID, forbiddenGroupIDs) {
|
||||
QString groupName = _groupNames[groupID];
|
||||
QHash<QUuid, GroupRank>& ranksForGroup = _groupRanks[groupID];
|
||||
|
@ -1743,7 +1743,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
QJsonObject postedObject(postedSettingsObject);
|
||||
|
||||
static const QString SECURITY_ROOT_KEY = "security";
|
||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||
static const QString AC_SUBNET_ALLOWLIST_KEY = "ac_subnet_allowlist";
|
||||
static const QString BROADCASTING_KEY = "broadcasting";
|
||||
static const QString WIZARD_KEY = "wizard";
|
||||
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
||||
|
@ -1863,7 +1863,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
|
||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||
rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) ||
|
||||
settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||
settingKey == AC_SUBNET_ALLOWLIST_KEY) {
|
||||
needRestart = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -2038,7 +2038,7 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() {
|
|||
}
|
||||
if (_groupIDs.contains(lowerGroupName)) {
|
||||
// we already know about this one. recall setGroupID in case the group has been
|
||||
// added to another section (the same group is found in both groups and blacklists).
|
||||
// added to another section (the same group is found in both groups and blocklists).
|
||||
changed = setGroupID(groupName, _groupIDs[lowerGroupName]);
|
||||
continue;
|
||||
}
|
||||
|
@ -2245,7 +2245,7 @@ QList<QUuid> DomainServerSettingsManager::getGroupIDs() {
|
|||
return result.values();
|
||||
}
|
||||
|
||||
QList<QUuid> DomainServerSettingsManager::getBlacklistGroupIDs() {
|
||||
QList<QUuid> DomainServerSettingsManager::getBlocklistGroupIDs() {
|
||||
QSet<QUuid> result;
|
||||
foreach (NodePermissionsKey groupKey, _groupForbiddens.keys()) {
|
||||
if (_groupForbiddens[groupKey]->isGroup()) {
|
||||
|
@ -2264,7 +2264,7 @@ QStringList DomainServerSettingsManager::getDomainServerGroupNames() {
|
|||
return result.values();
|
||||
}
|
||||
|
||||
QStringList DomainServerSettingsManager::getDomainServerBlacklistGroupNames() {
|
||||
QStringList DomainServerSettingsManager::getDomainServerBlocklistGroupNames() {
|
||||
// All names as listed in the domain server settings; not necessarily Directory Services groups.
|
||||
QSet<QString> result;
|
||||
foreach (NodePermissionsKey groupKey, _groupForbiddens.keys()) {
|
||||
|
|
|
@ -135,10 +135,10 @@ public:
|
|||
GroupRank getGroupRank(QUuid groupID, QUuid rankID) { return _groupRanks[groupID][rankID]; }
|
||||
|
||||
QList<QUuid> getGroupIDs();
|
||||
QList<QUuid> getBlacklistGroupIDs();
|
||||
QList<QUuid> getBlocklistGroupIDs();
|
||||
|
||||
QStringList getDomainServerGroupNames();
|
||||
QStringList getDomainServerBlacklistGroupNames();
|
||||
QStringList getDomainServerBlocklistGroupNames();
|
||||
|
||||
// these are used to locally cache the result of calling "/api/v1/groups/.../is_member/..." on Directory Services api
|
||||
void clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); }
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// Created by Wayne Chen on 10/18/18
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// Copyright 2024 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -377,13 +378,13 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
function onHandleLoginCompleted(): {
|
||||
function onHandleLoginCompleted() {
|
||||
console.log("Login Succeeded");
|
||||
loggingInBody.loadingSuccess();
|
||||
}
|
||||
|
||||
function onHandleLoginFailed() {
|
||||
console.log("Login Failed")
|
||||
console.log("Login Failed");
|
||||
loggingInSpinner.visible = false;
|
||||
loggingInGlyph.visible = false;
|
||||
var errorString = "";
|
||||
|
|
|
@ -354,7 +354,7 @@ Rectangle {
|
|||
font: avatarGainSliderText.font
|
||||
}
|
||||
RalewayRegular {
|
||||
// The slider for my card is special, it controls the master gain
|
||||
// The slider for my card is special, it controls the primary gain
|
||||
id: avatarGainSliderText;
|
||||
text: "People volume";
|
||||
size: 16;
|
||||
|
@ -645,7 +645,7 @@ Rectangle {
|
|||
font: noiseReductionThresholdSliderText.font
|
||||
}
|
||||
RalewayRegular {
|
||||
// The slider for my card is special, it controls the master gain
|
||||
// The slider for my card is special, it controls the primary gain
|
||||
id: noiseReductionThresholdSliderText;
|
||||
text: "Audio input threshold";
|
||||
size: 16;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// EntityScriptQMLWhitelist.qml
|
||||
// EntityScriptQMLAllowlist.qml
|
||||
// interface/resources/qml/hifi/dialogs/security
|
||||
//
|
||||
// Created by Kalila L. on 2019.12.05 | realities.dev | somnilibertas@gmail.com
|
||||
|
@ -8,7 +8,7 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Security Settings for the Entity Script QML Whitelist
|
||||
// Security Settings for the Entity Script QML Allowlist
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.8
|
||||
|
@ -23,25 +23,25 @@ import "../../../windows"
|
|||
Rectangle {
|
||||
id: parentBody;
|
||||
|
||||
function getWhitelistAsText() {
|
||||
var whitelist = Settings.getValue("private/settingsSafeURLS");
|
||||
var arrayWhitelist = whitelist.split(",").join("\n");
|
||||
return arrayWhitelist;
|
||||
function getAllowlistAsText() {
|
||||
var allowlist = Settings.getValue("private/settingsSafeURLS");
|
||||
var arrayAllowlist = allowlist.split(",").join("\n");
|
||||
return arrayAllowlist;
|
||||
}
|
||||
|
||||
function setWhitelistAsText(whitelistText) {
|
||||
Settings.setValue("private/settingsSafeURLS", whitelistText.text);
|
||||
function setAllowlistAsText(allowlistText) {
|
||||
Settings.setValue("private/settingsSafeURLS", allowlistText.text);
|
||||
|
||||
var originalSetString = whitelistText.text;
|
||||
var originalSetString = allowlistText.text;
|
||||
var originalSet = originalSetString.split(' ').join('');
|
||||
|
||||
var check = Settings.getValue("private/settingsSafeURLS");
|
||||
var arrayCheck = check.split(",").join("\n");
|
||||
|
||||
setWhitelistSuccess(arrayCheck === originalSet);
|
||||
setAllowlistSuccess(arrayCheck === originalSet);
|
||||
}
|
||||
|
||||
function setWhitelistSuccess(success) {
|
||||
function setAllowlistSuccess(success) {
|
||||
if (success) {
|
||||
notificationText.text = "Successfully saved settings.";
|
||||
} else {
|
||||
|
@ -49,20 +49,20 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleWhitelist(enabled) {
|
||||
Settings.setValue("private/whitelistEnabled", enabled);
|
||||
console.info("Toggling Whitelist to:", enabled);
|
||||
function toggleAllowlist(enabled) {
|
||||
Settings.setValue("private/allowlistEnabled", enabled);
|
||||
console.info("Toggling Allowlist to:", enabled);
|
||||
}
|
||||
|
||||
function initCheckbox() {
|
||||
var check = Settings.getValue("private/whitelistEnabled", false);
|
||||
var check = Settings.getValue("private/allowlistEnabled", false);
|
||||
|
||||
if (check) {
|
||||
whitelistEnabled.toggle();
|
||||
allowlistEnabled.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
anchors.fill: parent
|
||||
width: parent.width;
|
||||
height: 120;
|
||||
|
@ -70,7 +70,7 @@ Rectangle {
|
|||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: titleText;
|
||||
text: "Entity Script / QML Whitelist"
|
||||
text: "Entity Script / QML Allowlist"
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
|
@ -89,13 +89,13 @@ Rectangle {
|
|||
initCheckbox();
|
||||
}
|
||||
|
||||
id: whitelistEnabled;
|
||||
id: allowlistEnabled;
|
||||
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 10;
|
||||
onToggled: {
|
||||
toggleWhitelist(whitelistEnabled.checked)
|
||||
toggleAllowlist(allowlistEnabled.checked)
|
||||
}
|
||||
|
||||
Label {
|
||||
|
@ -115,7 +115,7 @@ Rectangle {
|
|||
width: parent.width;
|
||||
height: 250;
|
||||
anchors.top: titleText.bottom;
|
||||
|
||||
|
||||
ScrollView {
|
||||
id: textAreaScrollView
|
||||
anchors.fill: parent;
|
||||
|
@ -126,8 +126,8 @@ Rectangle {
|
|||
clip: false;
|
||||
|
||||
TextArea {
|
||||
id: whitelistTextArea
|
||||
text: getWhitelistAsText();
|
||||
id: allowlistTextArea
|
||||
text: getAllowlistAsText();
|
||||
onTextChanged: notificationText.text = "";
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
|
@ -136,7 +136,7 @@ Rectangle {
|
|||
color: "white";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
id: saveChanges
|
||||
anchors.topMargin: 5;
|
||||
|
@ -155,8 +155,8 @@ Rectangle {
|
|||
elide: Text.ElideRight
|
||||
}
|
||||
text: "Save Changes"
|
||||
onClicked: setWhitelistAsText(whitelistTextArea)
|
||||
|
||||
onClicked: setAllowlistAsText(allowlistTextArea)
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: notificationText;
|
||||
text: ""
|
||||
|
@ -170,15 +170,15 @@ Rectangle {
|
|||
anchors.rightMargin: 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: descriptionText;
|
||||
text:
|
||||
"The whitelist checks scripts and QML as they are loaded.<br/>
|
||||
text:
|
||||
"The allowlist checks scripts and QML as they are loaded.<br/>
|
||||
Therefore, if a script is cached or has no reason to load again,<br/>
|
||||
removing it from the whitelist will have no effect until<br/>
|
||||
removing it from the allowlist will have no effect until<br/>
|
||||
it is reloaded.<br/>
|
||||
Separate your whitelisted domains by line, not commas. e.g.
|
||||
Separate your allowlisted domains by line, not commas. e.g.
|
||||
<blockquote>
|
||||
<b>https://google.com/</b><br/>
|
||||
<b>hifi://the-spot/</b><br/>
|
||||
|
@ -186,7 +186,7 @@ Rectangle {
|
|||
<b>https://mydomain.here/</b>
|
||||
</blockquote>
|
||||
Ensure there are no spaces or whitespace.<br/><br/>
|
||||
For QML files, you can only whitelist each file individually<br/>
|
||||
For QML files, you can only allowlist each file individually<br/>
|
||||
ending with '.qml'."
|
||||
// Text size
|
||||
size: 16;
|
|
@ -5,7 +5,7 @@
|
|||
// Created by dr Karol Suprynowicz on 2024/03/24.
|
||||
// Copyright 2024 Overte e.V.
|
||||
//
|
||||
// Based on EntityScriptQMLWhitelist.qml
|
||||
// Based on EntityScriptQMLAllowlist.qml
|
||||
// Created by Kalila L. on 2019.12.05 | realities.dev | somnilibertas@gmail.com
|
||||
// Copyright 2019 Kalila L.
|
||||
//
|
||||
|
@ -27,15 +27,15 @@ import "../../../windows"
|
|||
Rectangle {
|
||||
id: parentBody;
|
||||
|
||||
function getWhitelistAsText() {
|
||||
var whitelist = Settings.getValue("private/scriptPermissionGetAvatarURLSafeURLs");
|
||||
var arrayWhitelist = whitelist.replace(",", "\n");
|
||||
return arrayWhitelist;
|
||||
function getAllowlistAsText() {
|
||||
var allowlist = Settings.getValue("private/scriptPermissionGetAvatarURLSafeURLs");
|
||||
var arrayAllowlist = allowlist.replace(",", "\n");
|
||||
return arrayAllowlist;
|
||||
}
|
||||
|
||||
function setWhitelistAsText(whitelistText) {
|
||||
Settings.setValue("private/scriptPermissionGetAvatarURLSafeURLs", whitelistText.text);
|
||||
notificationText.text = "Whitelist saved.";
|
||||
function setAllowlistAsText(allowlistText) {
|
||||
Settings.setValue("private/scriptPermissionGetAvatarURLSafeURLs", allowlistText.text);
|
||||
notificationText.text = "Allowlist saved.";
|
||||
}
|
||||
|
||||
function setAvatarProtection(enabled) {
|
||||
|
@ -65,7 +65,7 @@ Rectangle {
|
|||
height: 60;
|
||||
|
||||
CheckBox {
|
||||
id: whitelistEnabled;
|
||||
id: allowlistEnabled;
|
||||
|
||||
checked: Settings.getValue("private/scriptPermissionGetAvatarURLEnable", true);
|
||||
|
||||
|
@ -73,7 +73,7 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
anchors.topMargin: 10;
|
||||
onToggled: {
|
||||
setAvatarProtection(whitelistEnabled.checked)
|
||||
setAvatarProtection(allowlistEnabled.checked)
|
||||
}
|
||||
|
||||
Label {
|
||||
|
@ -104,8 +104,8 @@ Rectangle {
|
|||
clip: false;
|
||||
|
||||
TextArea {
|
||||
id: whitelistTextArea
|
||||
text: getWhitelistAsText();
|
||||
id: allowlistTextArea
|
||||
text: getAllowlistAsText();
|
||||
onTextChanged: notificationText.text = "";
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
|
@ -133,7 +133,7 @@ Rectangle {
|
|||
elide: Text.ElideRight
|
||||
}
|
||||
text: "Save Changes"
|
||||
onClicked: setWhitelistAsText(whitelistTextArea)
|
||||
onClicked: setAllowlistAsText(allowlistTextArea)
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: notificationText;
|
||||
|
|
|
@ -211,7 +211,7 @@ Flickable {
|
|||
wrapMode: Text.Wrap
|
||||
|
||||
Component.onCompleted: {
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU()));
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getPrimaryGPU()));
|
||||
var gpuModel = gpu.model;
|
||||
if (!gpuModel || gpuModel.length === 0) {
|
||||
gpuModel = "Unknown";
|
||||
|
@ -336,7 +336,7 @@ Flickable {
|
|||
textToCopy += "# CPU Cores: " + PlatformInfo.getNumLogicalCores() + "\n";
|
||||
textToCopy += "RAM: " + PlatformInfo.getTotalSystemMemoryMB() + " MB\n";
|
||||
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU()));
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getPrimaryGPU()));
|
||||
var gpuModel = gpu.model;
|
||||
if (!gpuModel || gpuModel.length === 0) {
|
||||
gpuModel = "Unknown";
|
||||
|
|
30
interface/resources/shaders/errorShader.frag
Normal file
30
interface/resources/shaders/errorShader.frag
Normal file
|
@ -0,0 +1,30 @@
|
|||
vec3 getErrorColor() {
|
||||
vec3 positionWS = iWorldOrientation * (_positionMS.xyz * iWorldScale) + iWorldPosition;
|
||||
float checkSize = 0.1;
|
||||
vec3 edges = round(mod(positionWS, vec3(checkSize)) / checkSize);
|
||||
float checkerboard = mod(edges.x + edges.y + edges.z, 2.0);
|
||||
return mix(vec3(1, 0, 1), vec3(0.0), checkerboard);
|
||||
}
|
||||
|
||||
// version 1
|
||||
vec3 getProceduralColor() {
|
||||
return getErrorColor();
|
||||
}
|
||||
|
||||
// version 2
|
||||
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
||||
diffuse = getErrorColor();
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// version 3
|
||||
float getProceduralFragment(inout ProceduralFragment data) {
|
||||
data.emissive = getErrorColor();
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// version 4
|
||||
float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition data) {
|
||||
data.emissive = getErrorColor();
|
||||
return 1.0;
|
||||
}
|
7
interface/resources/shaders/errorSkyboxShader.frag
Normal file
7
interface/resources/shaders/errorSkyboxShader.frag
Normal file
|
@ -0,0 +1,7 @@
|
|||
vec3 getSkyboxColor() {
|
||||
vec3 normal = normalize(_normal);
|
||||
float checkSize = 0.1;
|
||||
vec3 edges = round(mod(normal, vec3(checkSize)) / checkSize);
|
||||
float checkerboard = mod(edges.x + edges.y + edges.z, 2.0);
|
||||
return mix(vec3(1, 0, 1), vec3(0.0), checkerboard);
|
||||
}
|
|
@ -3293,9 +3293,9 @@ void Application::initializeUi() {
|
|||
{
|
||||
auto defaultUrlValidator = OffscreenQmlSurface::getUrlValidator();
|
||||
auto newValidator = [=](const QUrl& url) -> bool {
|
||||
QString whitelistPrefix = "[WHITELIST ENTITY SCRIPTS]";
|
||||
QString allowlistPrefix = "[ALLOWLIST ENTITY SCRIPTS]";
|
||||
QList<QString> safeURLS = { "" };
|
||||
safeURLS += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
safeURLS += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
|
||||
// PULL SAFEURLS FROM INTERFACE.JSON Settings
|
||||
|
||||
|
@ -3332,7 +3332,7 @@ void Application::initializeUi() {
|
|||
QmlContextCallback platformInfoCallback = [](QQmlContext* context) {
|
||||
context->setContextProperty("PlatformInfo", new PlatformInfoScriptingInterface());
|
||||
};
|
||||
OffscreenQmlSurface::addWhitelistContextHandler({
|
||||
OffscreenQmlSurface::addAllowlistContextHandler({
|
||||
QUrl{ "hifi/tablet/TabletAddressDialog.qml" },
|
||||
QUrl{ "hifi/Card.qml" },
|
||||
QUrl{ "hifi/Pal.qml" },
|
||||
|
@ -3342,7 +3342,7 @@ void Application::initializeUi() {
|
|||
QmlContextCallback ttsCallback = [](QQmlContext* context) {
|
||||
context->setContextProperty("TextToSpeech", DependencyManager::get<TTSScriptingInterface>().data());
|
||||
};
|
||||
OffscreenQmlSurface::addWhitelistContextHandler({
|
||||
OffscreenQmlSurface::addAllowlistContextHandler({
|
||||
QUrl{ "hifi/tts/TTS.qml" }
|
||||
}, ttsCallback);
|
||||
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/AvatarPackager.h"
|
||||
#include "AvatarBookmarks.h"
|
||||
#include <display-plugins/OpenGLDisplayPlugin.h>
|
||||
#include "DomainAccountManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "render/DrawStatus.h"
|
||||
|
@ -310,13 +311,13 @@ Menu::Menu() {
|
|||
}
|
||||
});
|
||||
|
||||
// Settings > Entity Script / QML Whitelist
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script / QML Whitelist");
|
||||
// Settings > Entity Script / QML Allowlist
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script / QML Allowlist");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
|
||||
tablet->pushOntoStack("hifi/dialogs/security/EntityScriptQMLWhitelist.qml");
|
||||
tablet->pushOntoStack("hifi/dialogs/security/EntityScriptQMLAllowlist.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
|
@ -540,7 +541,7 @@ Menu::Menu() {
|
|||
|
||||
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false);
|
||||
connect(action, &QAction::triggered, [action] {
|
||||
ModelMeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
|
||||
Procedural::enableProceduralShaders = action->isChecked();
|
||||
});
|
||||
|
||||
{
|
||||
|
@ -549,6 +550,13 @@ Menu::Menu() {
|
|||
drawStatusConfig, SLOT(setShowFade(bool)));
|
||||
}
|
||||
|
||||
{
|
||||
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ExtraLinearTosRGBConversion, 0, OpenGLDisplayPlugin::getExtraLinearToSRGBConversion());
|
||||
connect(action, &QAction::triggered, [action] {
|
||||
OpenGLDisplayPlugin::setExtraLinearToSRGBConversion(action->isChecked());
|
||||
});
|
||||
}
|
||||
|
||||
// Developer > Assets >>>
|
||||
// Menu item is not currently needed but code should be kept in case it proves useful again at some stage.
|
||||
//#define WANT_ASSET_MIGRATION
|
||||
|
|
|
@ -189,7 +189,7 @@ namespace MenuOption {
|
|||
const QString RunningScripts = "Running Scripts...";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
|
||||
const QString EntityScriptQMLWhitelist = "Entity Script / QML Whitelist";
|
||||
const QString EntityScriptQMLAllowlist = "Entity Script / QML Allowlist";
|
||||
const QString ScriptSecurity = "Script Security";
|
||||
const QString ShowTrackedObjects = "Show Tracked Objects";
|
||||
const QString SelfieCamera = "Selfie";
|
||||
|
@ -237,7 +237,8 @@ namespace MenuOption {
|
|||
const QString ComputeBlendshapes = "Compute Blendshapes";
|
||||
const QString HighlightTransitions = "Highlight Transitions";
|
||||
const QString MaterialProceduralShaders = "Enable Procedural Materials";
|
||||
}
|
||||
const QString ExtraLinearTosRGBConversion = "Extra Linear to sRGB Conversion";
|
||||
}
|
||||
|
||||
#endif // hifi_Menu_h
|
||||
|
||||
|
|
|
@ -75,13 +75,13 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
|
||||
// Ugly case that prevent us to run deferred everywhere...
|
||||
bool isDeferredCapable = platform::Profiler::isRenderMethodDeferredCapable();
|
||||
auto masterDisplay = platform::getDisplay(platform::getMasterDisplay());
|
||||
auto primaryDisplay = platform::getDisplay(platform::getPrimaryDisplay());
|
||||
|
||||
// eval recommended PPI and Scale
|
||||
float recommendedPpiScale = 1.0f;
|
||||
const float RECOMMENDED_PPI[] = { 200.0f, 200.0f, 120.f, 160.f, 250.f};
|
||||
if (!masterDisplay.empty() && masterDisplay.count(platform::keys::display::ppi)) {
|
||||
float ppi = masterDisplay[platform::keys::display::ppi];
|
||||
if (!primaryDisplay.empty() && primaryDisplay.count(platform::keys::display::ppi)) {
|
||||
float ppi = primaryDisplay[platform::keys::display::ppi];
|
||||
// only scale if the actual ppi is higher than the recommended ppi
|
||||
if (ppi > RECOMMENDED_PPI[preset]) {
|
||||
// make sure the scale is no less than a quarter
|
||||
|
|
|
@ -97,7 +97,7 @@ int main(int argc, const char* argv[]) {
|
|||
);
|
||||
QCommandLineOption protocolVersionOption(
|
||||
"protocolVersion",
|
||||
"Writes the protocol version base64 signature to a file?",
|
||||
"Writes the protocol version base64 signature to a file",
|
||||
"path"
|
||||
);
|
||||
QCommandLineOption noUpdaterOption(
|
||||
|
@ -275,10 +275,18 @@ int main(int argc, const char* argv[]) {
|
|||
"abortAfterInit",
|
||||
"Debug option. Aborts after initialization, right before the program starts running the event loop."
|
||||
);
|
||||
QCommandLineOption getProtocolVersionHashOption(
|
||||
"getProtocolVersionHash",
|
||||
"Debug option. Returns the network protocol version MD5 hash."
|
||||
);
|
||||
QCommandLineOption getProtocolVersionDataOption(
|
||||
"getProtocolVersionData",
|
||||
"Debug option. Returns the network protocol detailed data in JSON."
|
||||
);
|
||||
|
||||
// "--qmljsdebugger", which appears in output from "--help-all".
|
||||
// Those below don't seem to be optional.
|
||||
// --ignore-gpu-blacklist
|
||||
// --ignore-gpu-blocklist
|
||||
// --suppress-settings-reset
|
||||
|
||||
|
||||
|
@ -321,6 +329,8 @@ int main(int argc, const char* argv[]) {
|
|||
parser.addOption(abortAfterStartupOption);
|
||||
parser.addOption(abortAfterInitOption);
|
||||
parser.addOption(getPluginsOption);
|
||||
parser.addOption(getProtocolVersionHashOption);
|
||||
parser.addOption(getProtocolVersionDataOption);
|
||||
|
||||
|
||||
QString applicationPath;
|
||||
|
@ -455,6 +465,34 @@ int main(int argc, const char* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (parser.isSet(getProtocolVersionHashOption)) {
|
||||
std::cout << protocolVersionsSignatureHex().toStdString() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (parser.isSet(getProtocolVersionDataOption)) {
|
||||
auto protocolMap = protocolVersionsSignatureMap();
|
||||
QMetaEnum packetMetaEnum = QMetaEnum::fromType<PacketTypeEnum::Value>();
|
||||
|
||||
QJsonArray packetTypesList;
|
||||
auto keyList = protocolMap.keys();
|
||||
std::sort(keyList.begin(), keyList.end()); // Sort by numeric value
|
||||
|
||||
for(const auto packet : keyList) {
|
||||
QJsonObject data;
|
||||
int intValue = static_cast<int>(packet);
|
||||
QString keyName = packetMetaEnum.valueToKey(intValue);
|
||||
|
||||
data["name"] = keyName;
|
||||
data["value"] = intValue;
|
||||
data["version"] = versionForPacketType(packet);
|
||||
|
||||
packetTypesList.append(data);
|
||||
}
|
||||
|
||||
std::cout << QJsonDocument(packetTypesList).toJson().toStdString() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
|
||||
QDir applicationDir(applicationPath);
|
||||
|
|
|
@ -408,9 +408,9 @@ CollisionRegion CollisionPick::getMathematicalPick() const {
|
|||
void CollisionPick::filterIntersections(std::vector<ContactTestResult>& intersections) const {
|
||||
const QVector<QUuid>& ignoreItems = getIgnoreItems();
|
||||
const QVector<QUuid>& includeItems = getIncludeItems();
|
||||
bool isWhitelist = !includeItems.empty();
|
||||
bool isAllowlist = !includeItems.empty();
|
||||
|
||||
if (!isWhitelist && ignoreItems.empty()) {
|
||||
if (!isAllowlist && ignoreItems.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ void CollisionPick::filterIntersections(std::vector<ContactTestResult>& intersec
|
|||
for (int i = 0; i < n; i++) {
|
||||
auto& intersection = intersections[i];
|
||||
const QUuid& id = intersection.foundID;
|
||||
if (!ignoreItems.contains(id) && (!isWhitelist || includeItems.contains(id))) {
|
||||
if (!ignoreItems.contains(id) && (!isAllowlist || includeItems.contains(id))) {
|
||||
filteredIntersections.push_back(intersection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -533,7 +533,7 @@ void Audio::setAvatarGain(float gain) {
|
|||
}
|
||||
|
||||
withWriteLock([&] {
|
||||
// ask the NodeList to set the master avatar gain
|
||||
// ask the NodeList to set the primary avatar gain
|
||||
DependencyManager::get<NodeList>()->setAvatarGain(QUuid(), gain);
|
||||
});
|
||||
|
||||
|
|
|
@ -182,8 +182,8 @@ bool PlatformInfoScriptingInterface::isStandalone() {
|
|||
int PlatformInfoScriptingInterface::getNumCPUs() {
|
||||
return platform::getNumCPUs();
|
||||
}
|
||||
int PlatformInfoScriptingInterface::getMasterCPU() {
|
||||
return platform::getMasterCPU();
|
||||
int PlatformInfoScriptingInterface::getPrimaryCPU() {
|
||||
return platform::getPrimaryCPU();
|
||||
}
|
||||
QString PlatformInfoScriptingInterface::getCPU(int index) {
|
||||
auto desc = platform::getCPU(index);
|
||||
|
@ -193,8 +193,8 @@ QString PlatformInfoScriptingInterface::getCPU(int index) {
|
|||
int PlatformInfoScriptingInterface::getNumGPUs() {
|
||||
return platform::getNumGPUs();
|
||||
}
|
||||
int PlatformInfoScriptingInterface::getMasterGPU() {
|
||||
return platform::getMasterGPU();
|
||||
int PlatformInfoScriptingInterface::getPrimaryGPU() {
|
||||
return platform::getPrimaryGPU();
|
||||
}
|
||||
QString PlatformInfoScriptingInterface::getGPU(int index) {
|
||||
auto desc = platform::getGPU(index);
|
||||
|
@ -204,8 +204,8 @@ QString PlatformInfoScriptingInterface::getGPU(int index) {
|
|||
int PlatformInfoScriptingInterface::getNumDisplays() {
|
||||
return platform::getNumDisplays();
|
||||
}
|
||||
int PlatformInfoScriptingInterface::getMasterDisplay() {
|
||||
return platform::getMasterDisplay();
|
||||
int PlatformInfoScriptingInterface::getPrimaryDisplay() {
|
||||
return platform::getPrimaryDisplay();
|
||||
}
|
||||
QString PlatformInfoScriptingInterface::getDisplay(int index) {
|
||||
auto desc = platform::getDisplay(index);
|
||||
|
|
|
@ -106,8 +106,8 @@ public slots:
|
|||
* @function PlatformInfo.getGraphicsCardType
|
||||
* @returns {string} The model of the graphics card currently being used.
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
* Use <code>JSON.parse({@link PlatformInfo.getGPU|PlatformInfo.getGPU(}
|
||||
* {@link PlatformInfo.getMasterGPU|PlatformInfo.getMasterGPU() )}).model</code>
|
||||
* Use <code>JSON.parse({@link PlatformInfo.getGPU|PlatformInfo.getGPU(}
|
||||
* {@link PlatformInfo.getPrimaryGPU|PlatformInfo.getPrimaryGPU() )}).model</code>
|
||||
* instead.
|
||||
*/
|
||||
QString getGraphicsCardType();
|
||||
|
@ -149,11 +149,11 @@ public slots:
|
|||
int getNumCPUs();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the index number of the master CPU.
|
||||
* @function PlatformInfo.getMasterCPU
|
||||
* @returns {number} The index of the master CPU.
|
||||
* Gets the index number of the primary CPU.
|
||||
* @function PlatformInfo.getPrimaryCPU
|
||||
* @returns {number} The index of the primary CPU.
|
||||
*/
|
||||
int getMasterCPU();
|
||||
int getPrimaryCPU();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the platform description of a CPU.
|
||||
|
@ -178,11 +178,11 @@ public slots:
|
|||
int getNumGPUs();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the index number of the master GPU.
|
||||
* @function PlatformInfo.getMasterGPU
|
||||
* @returns {number} The index of the master GPU.
|
||||
* Gets the index number of the primary GPU.
|
||||
* @function PlatformInfo.getPrimaryGPU
|
||||
* @returns {number} The index of the primary GPU.
|
||||
*/
|
||||
int getMasterGPU();
|
||||
int getPrimaryGPU();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the platform description of a GPU.
|
||||
|
@ -207,11 +207,11 @@ public slots:
|
|||
int getNumDisplays();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the index number of the master display.
|
||||
* @function PlatformInfo.getMasterDisplay
|
||||
* @returns {number} The index of the master display.
|
||||
* Gets the index number of the primary display.
|
||||
* @function PlatformInfo.getPrimaryDisplay
|
||||
* @returns {number} The index of the primary display.
|
||||
*/
|
||||
int getMasterDisplay();
|
||||
int getPrimaryDisplay();
|
||||
|
||||
/*@jsdoc
|
||||
* Gets the platform description of a display.
|
||||
|
|
|
@ -221,8 +221,8 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
|
|||
|
||||
Application::setupQmlSurface(quickView->rootContext(), true);
|
||||
|
||||
//add any whitelisted callbacks
|
||||
OffscreenUi::applyWhiteList(sourceUrl, quickView->rootContext());
|
||||
//add any allowlisted callbacks
|
||||
OffscreenUi::applyAllowList(sourceUrl, quickView->rootContext());
|
||||
|
||||
/*@jsdoc
|
||||
* Configures how a <code>NATIVE</code> window is displayed.
|
||||
|
|
|
@ -538,7 +538,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
|||
}
|
||||
}
|
||||
} else if (targetType == IKTarget::Type::HmdHead) {
|
||||
// An HmdHead target slaves the orientation of the end-effector by distributing rotation
|
||||
// An HmdHead target workers the orientation of the end-effector by distributing rotation
|
||||
// deltas up the hierarchy. Its target position is enforced later (by shifting the hips).
|
||||
deltaRotation = target.getRotation() * glm::inverse(tipOrientation);
|
||||
const float ANGLE_DISTRIBUTION_FACTOR = 0.45f;
|
||||
|
|
|
@ -71,11 +71,11 @@ public:
|
|||
|
||||
using IgnoreBox = AABox;
|
||||
|
||||
// called from single AudioMixerSlave while processing packets for node
|
||||
// called from single AudioMixerWorker while processing packets for node
|
||||
void enableIgnoreBox();
|
||||
void disableIgnoreBox() { _isIgnoreBoxEnabled = false; }
|
||||
|
||||
// thread-safe, called from AudioMixerSlave(s) while preparing mixes
|
||||
// thread-safe, called from AudioMixerWorker(s) while preparing mixes
|
||||
bool isIgnoreBoxEnabled() const { return _isIgnoreBoxEnabled; }
|
||||
const IgnoreBox& getIgnoreBox() const { return _ignoreBox; }
|
||||
|
||||
|
|
|
@ -4417,9 +4417,9 @@ bs_new ()
|
|||
bs = (Bit_stream_struc *) calloc(1, sizeof(Bit_stream_struc));
|
||||
g_return_val_if_fail (bs != NULL, NULL);
|
||||
|
||||
bs->master.cur_bit = 8;
|
||||
bs->master.size = 0;
|
||||
bs->master.cur_used = 0;
|
||||
bs->primary.cur_bit = 8;
|
||||
bs->primary.size = 0;
|
||||
bs->primary.cur_used = 0;
|
||||
bs->read.cur_bit = 8;
|
||||
bs->read.size = 0;
|
||||
bs->read.cur_used = 0;
|
||||
|
@ -4443,11 +4443,11 @@ bs_set_data (Bit_stream_struc * bs, const guint8 * data, gsize size)
|
|||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (size != 0, FALSE);
|
||||
|
||||
bs->master.data = data;
|
||||
bs->master.cur_byte = (guint8 *) data;
|
||||
bs->master.size = size;
|
||||
bs->master.bitpos = 0;
|
||||
bs->master.cur_used = 0;
|
||||
bs->primary.data = data;
|
||||
bs->primary.cur_byte = (guint8 *) data;
|
||||
bs->primary.size = size;
|
||||
bs->primary.bitpos = 0;
|
||||
bs->primary.cur_used = 0;
|
||||
bs_reset (bs);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -4494,7 +4494,7 @@ bs_eat (Bit_stream_struc * bs, BSReader * read, guint32 Nbits)
|
|||
}
|
||||
}
|
||||
|
||||
/* Advance the master position by Nbits */
|
||||
/* Advance the primary position by Nbits */
|
||||
void
|
||||
bs_consume (Bit_stream_struc * bs, guint32 Nbits)
|
||||
{
|
||||
|
@ -4503,7 +4503,7 @@ bs_consume (Bit_stream_struc * bs, guint32 Nbits)
|
|||
GST_DEBUG ("%d Consumed %d bits to end at %" G_GUINT64_FORMAT,
|
||||
n++, Nbits, bs_pos (bs) + Nbits);
|
||||
#endif
|
||||
bs_eat (bs, &bs->master, Nbits);
|
||||
bs_eat (bs, &bs->primary, Nbits);
|
||||
}
|
||||
|
||||
/* Advance the read position by Nbits */
|
||||
|
|
|
@ -197,10 +197,10 @@ typedef struct BSReader
|
|||
|
||||
typedef struct Bit_stream_struc
|
||||
{
|
||||
BSReader master; /* Master tracking position, advanced
|
||||
BSReader primary; /* Primary tracking position, advanced
|
||||
* by bs_consume() */
|
||||
BSReader read; /* Current read position, set back to the
|
||||
* master by bs_reset() */
|
||||
* primary by bs_reset() */
|
||||
} Bit_stream_struc;
|
||||
|
||||
/* Create and initialise a new bitstream reader */
|
||||
|
@ -209,25 +209,25 @@ Bit_stream_struc *bs_new ();
|
|||
/* Release a bitstream reader */
|
||||
void bs_free (Bit_stream_struc * bs);
|
||||
|
||||
/* Reset the current read position to the master position */
|
||||
/* Reset the current read position to the primary position */
|
||||
static inline void
|
||||
bs_reset (Bit_stream_struc * bs)
|
||||
{
|
||||
memcpy (&bs->read, &bs->master, sizeof (BSReader));
|
||||
memcpy (&bs->read, &bs->primary, sizeof (BSReader));
|
||||
}
|
||||
|
||||
/* Reset master and read states */
|
||||
/* Reset primary and read states */
|
||||
static inline void
|
||||
bs_flush (Bit_stream_struc * bs)
|
||||
{
|
||||
g_return_if_fail (bs != NULL);
|
||||
|
||||
bs->master.cur_bit = 8;
|
||||
bs->master.size = 0;
|
||||
bs->master.cur_used = 0;
|
||||
bs->master.cur_byte = NULL;
|
||||
bs->master.data = NULL;
|
||||
bs->master.bitpos = 0;
|
||||
bs->primary.cur_bit = 8;
|
||||
bs->primary.size = 0;
|
||||
bs->primary.cur_used = 0;
|
||||
bs->primary.cur_byte = NULL;
|
||||
bs->primary.data = NULL;
|
||||
bs->primary.bitpos = 0;
|
||||
|
||||
bs_reset (bs);
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ bs_flush (Bit_stream_struc * bs)
|
|||
/* Set data as the stream for processing */
|
||||
gboolean bs_set_data (Bit_stream_struc * bs, const guint8 * data, gsize size);
|
||||
|
||||
/* Advance the master position by Nbits */
|
||||
/* Advance the primary position by Nbits */
|
||||
void bs_consume (Bit_stream_struc * bs, guint32 Nbits);
|
||||
|
||||
/* Number of bits available for reading */
|
||||
|
@ -253,14 +253,14 @@ void bs_skipbits (Bit_stream_struc * bs, guint32 N);
|
|||
/* give number of consumed bytes */
|
||||
static inline gsize bs_get_consumed (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.cur_used;
|
||||
return bs->primary.cur_used;
|
||||
}
|
||||
|
||||
/* Current bitstream position in bits */
|
||||
static inline guint64
|
||||
bs_pos (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.bitpos;
|
||||
return bs->primary.bitpos;
|
||||
}
|
||||
|
||||
/* Current read bitstream position in bits */
|
||||
|
|
|
@ -1704,7 +1704,7 @@ protected:
|
|||
void unpackSkeletonModelURL(const QByteArray& data);
|
||||
void unpackSkeletonData(const QByteArray& data);
|
||||
|
||||
// isReplicated will be true on downstream Avatar Mixers and their clients, but false on the upstream "master"
|
||||
// isReplicated will be true on downstream Avatar Mixers and their clients, but false on the upstream "primary"
|
||||
// Audio Mixer that the replicated avatar is connected to.
|
||||
bool _isReplicated{ false };
|
||||
|
||||
|
|
|
@ -112,14 +112,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() {
|
|||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
gpu::PipelinePointer Basic2DWindowOpenGLDisplayPlugin::getRenderTexturePipeline() {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
return _linearToSRGBPipeline;
|
||||
#else
|
||||
return _drawTexturePipeline;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
auto& virtualPadManager = VirtualPad::Manager::instance();
|
||||
|
|
|
@ -37,8 +37,6 @@ public:
|
|||
|
||||
virtual void pluginUpdate() override {};
|
||||
|
||||
virtual gpu::PipelinePointer getRenderTexturePipeline() override;
|
||||
|
||||
protected:
|
||||
mutable bool _isThrottled = false;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <gl/GLEscrow.h>
|
||||
#include <gl/Context.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <gpu/FrameIO.h>
|
||||
|
@ -57,6 +58,8 @@ using namespace shader::gpu::program;
|
|||
|
||||
extern QThread* RENDER_THREAD;
|
||||
|
||||
Setting::Handle<bool> OpenGLDisplayPlugin::_extraLinearToSRGBConversionSetting("extraLinearToSRGBConversion", false);
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
using Mutex = std::mutex;
|
||||
using Condition = std::condition_variable;
|
||||
|
@ -956,5 +959,16 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
|
|||
}
|
||||
|
||||
gpu::PipelinePointer OpenGLDisplayPlugin::getRenderTexturePipeline() {
|
||||
return _drawTexturePipeline;
|
||||
#ifdef USE_GLES
|
||||
if (!_extraLinearToSRGBConversionSetting.isSet()) {
|
||||
const gl::ContextInfo &contextInfo = gl::ContextInfo::get();
|
||||
_extraLinearToSRGBConversionSetting.set(std::find(contextInfo.extensions.cbegin(), contextInfo.extensions.cend(), "GL_EXT_framebuffer_sRGB") == contextInfo.extensions.cend());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getExtraLinearToSRGBConversion()) {
|
||||
return _linearToSRGBPipeline;
|
||||
} else {
|
||||
return _drawTexturePipeline;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtGui/QImage>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
|
@ -86,6 +87,9 @@ public:
|
|||
QOpenGLFramebufferObject* target,
|
||||
GLsync* fenceSync) override;
|
||||
|
||||
static void setExtraLinearToSRGBConversion(bool value) { _extraLinearToSRGBConversionSetting.set(value); }
|
||||
static bool getExtraLinearToSRGBConversion() { return _extraLinearToSRGBConversionSetting.get(); };
|
||||
|
||||
protected:
|
||||
friend class PresentThread;
|
||||
|
||||
|
@ -201,4 +205,7 @@ protected:
|
|||
|
||||
QImage getScreenshot(float aspectRatio);
|
||||
QImage getSecondaryCameraScreenshot();
|
||||
|
||||
private:
|
||||
static Setting::Handle<bool> _extraLinearToSRGBConversionSetting;
|
||||
};
|
||||
|
|
|
@ -65,8 +65,8 @@ EntityTree::~EntityTree() {
|
|||
//eraseAllOctreeElements(false); // KEEP THIS
|
||||
}
|
||||
|
||||
void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) {
|
||||
_entityScriptSourceWhitelist = entityScriptSourceWhitelist.split(',', Qt::SkipEmptyParts);
|
||||
void EntityTree::setEntityScriptSourceAllowlist(const QString& entityScriptSourceAllowlist) {
|
||||
_entityScriptSourceAllowlist = entityScriptSourceAllowlist.split(',', Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1411,17 +1411,17 @@ void EntityTree::bumpTimestamp(EntityItemProperties& properties) { //fixme put c
|
|||
properties.setLastEdited(properties.getLastEdited() + LAST_EDITED_SERVERSIDE_BUMP);
|
||||
}
|
||||
|
||||
bool EntityTree::isScriptInWhitelist(const QString& scriptProperty) {
|
||||
bool EntityTree::isScriptInAllowlist(const QString& scriptProperty) {
|
||||
|
||||
// grab a URL representation of the entity script so we can check the host for this script
|
||||
auto entityScriptURL = QUrl::fromUserInput(scriptProperty);
|
||||
|
||||
for (const auto& whiteListedPrefix : _entityScriptSourceWhitelist) {
|
||||
auto whiteListURL = QUrl::fromUserInput(whiteListedPrefix);
|
||||
for (const auto& allowListedPrefix : _entityScriptSourceAllowlist) {
|
||||
auto allowListURL = QUrl::fromUserInput(allowListedPrefix);
|
||||
|
||||
// check if this script URL matches the whitelist domain and, optionally, is beneath the path
|
||||
if (entityScriptURL.host().compare(whiteListURL.host(), Qt::CaseInsensitive) == 0 &&
|
||||
entityScriptURL.path().startsWith(whiteListURL.path(), Qt::CaseInsensitive)) {
|
||||
// check if this script URL matches the allowlist domain and, optionally, is beneath the path
|
||||
if (entityScriptURL.host().compare(allowListURL.host(), Qt::CaseInsensitive) == 0 &&
|
||||
entityScriptURL.path().startsWith(allowListURL.path(), Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1504,18 +1504,18 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
}
|
||||
}
|
||||
|
||||
if (validEditPacket && !_entityScriptSourceWhitelist.isEmpty()) {
|
||||
if (validEditPacket && !_entityScriptSourceAllowlist.isEmpty()) {
|
||||
|
||||
bool wasDeletedBecauseOfClientScript = false;
|
||||
|
||||
// check the client entity script to make sure its URL is in the whitelist
|
||||
// check the client entity script to make sure its URL is in the allowlist
|
||||
if (!properties.getScript().isEmpty()) {
|
||||
bool clientScriptPassedWhitelist = isScriptInWhitelist(properties.getScript());
|
||||
bool clientScriptPassedAllowlist = isScriptInAllowlist(properties.getScript());
|
||||
|
||||
if (!clientScriptPassedWhitelist) {
|
||||
if (!clientScriptPassedAllowlist) {
|
||||
if (wantEditLogging()) {
|
||||
qCDebug(entities) << "User [" << senderNode->getUUID()
|
||||
<< "] attempting to set entity script not on whitelist, edit rejected";
|
||||
<< "] attempting to set entity script not on allowlist, edit rejected";
|
||||
}
|
||||
|
||||
// If this was an add, we also want to tell the client that sent this edit that the entity was not added.
|
||||
|
@ -1530,20 +1530,20 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
}
|
||||
}
|
||||
|
||||
// check all server entity scripts to make sure their URLs are in the whitelist
|
||||
// check all server entity scripts to make sure their URLs are in the allowlist
|
||||
if (!properties.getServerScripts().isEmpty()) {
|
||||
bool serverScriptPassedWhitelist = isScriptInWhitelist(properties.getServerScripts());
|
||||
bool serverScriptPassedAllowlist = isScriptInAllowlist(properties.getServerScripts());
|
||||
|
||||
if (!serverScriptPassedWhitelist) {
|
||||
if (!serverScriptPassedAllowlist) {
|
||||
if (wantEditLogging()) {
|
||||
qCDebug(entities) << "User [" << senderNode->getUUID()
|
||||
<< "] attempting to set server entity script not on whitelist, edit rejected";
|
||||
<< "] attempting to set server entity script not on allowlist, edit rejected";
|
||||
}
|
||||
|
||||
// If this was an add, we also want to tell the client that sent this edit that the entity was not added.
|
||||
if (isAdd) {
|
||||
// Make sure we didn't already need to send back a delete because the client script failed
|
||||
// the whitelist check
|
||||
// the allowlist check
|
||||
if (!wasDeletedBecauseOfClientScript) {
|
||||
QWriteLocker locker(&_recentlyDeletedEntitiesLock);
|
||||
_recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), entityItemID);
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
|
||||
|
||||
void setEntityMaxTmpLifetime(float maxTmpEntityLifetime) { _maxTmpEntityLifetime = maxTmpEntityLifetime; }
|
||||
void setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist);
|
||||
void setEntityScriptSourceAllowlist(const QString& entityScriptSourceAllowlist);
|
||||
|
||||
/// Implements our type specific root element factory
|
||||
virtual OctreeElementPointer createNewElement(unsigned char* octalCode = NULL) override;
|
||||
|
@ -300,7 +300,7 @@ protected:
|
|||
|
||||
void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode);
|
||||
|
||||
bool isScriptInWhitelist(const QString& scriptURL);
|
||||
bool isScriptInAllowlist(const QString& scriptURL);
|
||||
|
||||
QReadWriteLock _newlyCreatedHooksLock;
|
||||
QVector<NewlyCreatedEntityHook*> _newlyCreatedHooks;
|
||||
|
@ -363,7 +363,7 @@ protected:
|
|||
|
||||
bool filterProperties(const EntityItemPointer& existingEntity, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, FilterType filterType) const;
|
||||
bool _hasEntityEditFilter{ false };
|
||||
QStringList _entityScriptSourceWhitelist;
|
||||
QStringList _entityScriptSourceAllowlist;
|
||||
|
||||
MovingEntitiesOperator _entityMover;
|
||||
QHash<EntityItemID, EntityItemPointer> _entitiesToAdd;
|
||||
|
|
|
@ -126,7 +126,7 @@ protected:
|
|||
const Shaders _shaders;
|
||||
|
||||
|
||||
// The type of the shader, the master key
|
||||
// The type of the shader, the primary key
|
||||
const Type _type;
|
||||
|
||||
// Number of attempts to compile the shader
|
||||
|
|
|
@ -405,7 +405,7 @@ public:
|
|||
Stamp getDataStamp() const { return _storage->getStamp(); }
|
||||
|
||||
// The theoretical size in bytes of data stored in the texture
|
||||
// For the master (level) first level of mip
|
||||
// For the primary (level) first level of mip
|
||||
Size getSize() const override { return _size; }
|
||||
|
||||
// Size and format
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Created by Stephen Birarda on 2/18/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2023 Overte e.V.
|
||||
// Copyright 2023-2024 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -696,7 +696,8 @@ void AccountManager::setAccessTokens(const QString& response) {
|
|||
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|
||||
|| !rootObject.contains("token_type")) {
|
||||
// TODO: error handling - malformed token response
|
||||
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
||||
qCWarning(networking) << "Error setting access token. Received a response for password grant that is missing one or more expected values.";
|
||||
qCWarning(networking) << "Response:" << QJsonDocument(rootObject).toJson(QJsonDocument::Compact);
|
||||
} else {
|
||||
// clear the path from the response URL so we have the right root URL for this access token
|
||||
QUrl rootURL = rootObject.contains("url") ? rootObject["url"].toString() : _authURL;
|
||||
|
@ -714,7 +715,7 @@ void AccountManager::setAccessTokens(const QString& response) {
|
|||
}
|
||||
} else {
|
||||
// TODO: error handling
|
||||
qCDebug(networking) << "Error in response for password grant -" << rootObject["error_description"].toString();
|
||||
qCWarning(networking) << "Error in response for password grant -" << rootObject["error"].toString();
|
||||
emit loginFailed();
|
||||
}
|
||||
}
|
||||
|
@ -731,7 +732,8 @@ void AccountManager::requestAccessTokenFinished() {
|
|||
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|
||||
|| !rootObject.contains("token_type")) {
|
||||
// TODO: error handling - malformed token response
|
||||
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
||||
qCWarning(networking) << "Error requesting access token. Received a response for password grant that is missing one or more expected values.";
|
||||
qCWarning(networking) << "Response:" << QJsonDocument(rootObject).toJson(QJsonDocument::Compact);
|
||||
} else {
|
||||
// clear the path from the response URL so we have the right root URL for this access token
|
||||
QUrl rootURL = requestReply->url();
|
||||
|
@ -750,7 +752,7 @@ void AccountManager::requestAccessTokenFinished() {
|
|||
}
|
||||
} else {
|
||||
// TODO: error handling
|
||||
qCDebug(networking) << "Error in response for password grant -" << rootObject["error_description"].toString();
|
||||
qCWarning(networking) << "Error in response for password grant -" << rootObject["error"].toString();
|
||||
emit loginFailed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1250,7 +1250,7 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) {
|
|||
setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.02059991f)));
|
||||
|
||||
if (nodeID.isNull()) {
|
||||
qCDebug(networking) << "Sending Set MASTER Avatar Gain packet with Gain:" << gain;
|
||||
qCDebug(networking) << "Sending Set PRIMARY Avatar Gain packet with Gain:" << gain;
|
||||
|
||||
sendPacket(std::move(setAvatarGainPacket), *audioMixer);
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ void UserActivityLogger::changedDomain(QString domainURL) {
|
|||
}
|
||||
|
||||
void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceName) {
|
||||
static QStringList DEVICE_BLACKLIST = {
|
||||
static QStringList DEVICE_BLOCKLIST = {
|
||||
"Desktop",
|
||||
"NullDisplayPlugin",
|
||||
"3D TV - Side by Side Stereo",
|
||||
|
@ -145,7 +145,7 @@ void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceNam
|
|||
"Keyboard/Mouse"
|
||||
};
|
||||
|
||||
if (DEVICE_BLACKLIST.contains(deviceName) || deviceName.isEmpty()) {
|
||||
if (DEVICE_BLOCKLIST.contains(deviceName) || deviceName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,10 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion) {
|
|||
|
||||
static QByteArray protocolVersionSignature;
|
||||
static QString protocolVersionSignatureBase64;
|
||||
static QString protocolVersionSignatureHex;
|
||||
static QMap<PacketType, uint8_t> protocolVersionMap;
|
||||
|
||||
|
||||
static void ensureProtocolVersionsSignature() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
|
@ -139,12 +143,14 @@ static void ensureProtocolVersionsSignature() {
|
|||
stream << numberOfProtocols;
|
||||
for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) {
|
||||
uint8_t packetTypeVersion = static_cast<uint8_t>(versionForPacketType(static_cast<PacketType>(packetType)));
|
||||
protocolVersionMap[static_cast<PacketType>(packetType)] = packetTypeVersion;
|
||||
stream << packetTypeVersion;
|
||||
}
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.addData(buffer);
|
||||
protocolVersionSignature = hash.result();
|
||||
protocolVersionSignatureBase64 = protocolVersionSignature.toBase64();
|
||||
protocolVersionSignatureHex = protocolVersionSignature.toHex(0);
|
||||
});
|
||||
}
|
||||
QByteArray protocolVersionsSignature() {
|
||||
|
@ -161,3 +167,13 @@ QString protocolVersionsSignatureBase64() {
|
|||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionSignatureBase64;
|
||||
}
|
||||
|
||||
QString protocolVersionsSignatureHex() {
|
||||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionSignatureHex;
|
||||
}
|
||||
|
||||
QMap<PacketType, uint8_t> protocolVersionsSignatureMap() {
|
||||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionMap;
|
||||
}
|
|
@ -31,8 +31,15 @@ class PacketTypeEnum {
|
|||
Q_GADGET
|
||||
Q_ENUMS(Value)
|
||||
public:
|
||||
// If adding a new packet packetType, you can replace one marked usable or add at the end.
|
||||
// This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
||||
|
||||
/**
|
||||
* @brief Packet type identifier
|
||||
*
|
||||
* Identifies the type of packet being sent.
|
||||
*
|
||||
* @note If adding a new packet packetType, you can replace one marked usable or add at the end.
|
||||
* @note This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
||||
*/
|
||||
enum class Value : uint8_t {
|
||||
Unknown,
|
||||
DomainConnectRequestPending,
|
||||
|
@ -143,6 +150,8 @@ public:
|
|||
NUM_PACKET_TYPE
|
||||
};
|
||||
|
||||
Q_ENUM(Value)
|
||||
|
||||
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> getReplicatedPacketMapping() {
|
||||
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> REPLICATED_PACKET_MAPPING {
|
||||
{ PacketTypeEnum::Value::MicrophoneAudioNoEcho, PacketTypeEnum::Value::ReplicatedMicrophoneAudioNoEcho },
|
||||
|
@ -219,10 +228,60 @@ const int NUM_BYTES_MD5_HASH = 16;
|
|||
// NOTE: There is a max limit of 255, hopefully we have a better way to manage this by then.
|
||||
typedef uint8_t PacketVersion;
|
||||
|
||||
/**
|
||||
* @brief Returns the version number of the given packet type
|
||||
*
|
||||
* If the implementation of a packet type is modified in an incompatible way, the implementation
|
||||
* of this function needs to be modified to return an incremented value.
|
||||
*
|
||||
* This is used to determine whether the protocol is compatible between client and server.
|
||||
*
|
||||
* @note Version is limited to a max of 255.
|
||||
*
|
||||
* @param packetType Type of packet
|
||||
* @return PacketVersion Version
|
||||
*/
|
||||
PacketVersion versionForPacketType(PacketType packetType);
|
||||
QByteArray protocolVersionsSignature(); /// returns a unique signature for all the current protocols
|
||||
|
||||
/**
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* This computes a MD5 hash that expresses the state of the protocol's specification. The calculation
|
||||
* is done in ensureProtocolVersionsSignature and accounts for the following:
|
||||
*
|
||||
* * Number of known packet types
|
||||
* * versionForPacketType(type) for each packet type.
|
||||
*
|
||||
* There's no provision for backwards compatibility, anything that changes this calculation is a protocol break.
|
||||
*
|
||||
* @return QByteArray MD5 digest as a byte array
|
||||
*/
|
||||
QByteArray protocolVersionsSignature();
|
||||
|
||||
/***
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* Same as protocolVersionsSignature(), in base64.
|
||||
*/
|
||||
QString protocolVersionsSignatureBase64();
|
||||
|
||||
/***
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* Same as protocolVersionsSignature(), in hex;
|
||||
*/
|
||||
QString protocolVersionsSignatureHex();
|
||||
|
||||
/***
|
||||
* @brief Returns the data used to compute the protocol version
|
||||
*
|
||||
* The key is the packet type. The value is the version for that packet type.
|
||||
*
|
||||
* Used for aiding in development.
|
||||
*/
|
||||
QMap<PacketType, uint8_t> protocolVersionsSignatureMap();
|
||||
|
||||
|
||||
#if (PR_BUILD || DEV_BUILD)
|
||||
void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debugging version negotiation
|
||||
#endif
|
||||
|
@ -428,4 +487,5 @@ enum class AvatarQueryVersion : PacketVersion {
|
|||
ConicalFrustums = 22
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -655,7 +655,7 @@ uint8_t EntityMotionState::getSimulationPriority() const {
|
|||
return _entity->getSimulationPriority();
|
||||
}
|
||||
|
||||
void EntityMotionState::slaveBidPriority() {
|
||||
void EntityMotionState::workerBidPriority() {
|
||||
_bumpedPriority = glm::max(_bumpedPriority, _entity->getSimulationPriority());
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ protected:
|
|||
void updateServerPhysicsVariables();
|
||||
bool remoteSimulationOutOfSync(uint32_t simulationStep);
|
||||
|
||||
void slaveBidPriority(); // computeNewBidPriority() with value stored in _entity
|
||||
void workerBidPriority(); // computeNewBidPriority() with value stored in _entity
|
||||
|
||||
void clearObjectVelocities() const;
|
||||
|
||||
|
|
|
@ -602,7 +602,7 @@ void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
|
|||
// in the EntityMotionState::_serverFoo variables (please see comments in EntityMotionState.h)
|
||||
// therefore we need to immediately send an update so that the values stored are what we're
|
||||
// "telling" the server rather than what we've been "hearing" from the server.
|
||||
_bids[i]->slaveBidPriority();
|
||||
_bids[i]->workerBidPriority();
|
||||
_bids[i]->sendUpdate(_entityPacketSender, numSubsteps);
|
||||
|
||||
addOwnership(_bids[i]);
|
||||
|
|
|
@ -21,15 +21,15 @@ bool enumeratePlatform();
|
|||
|
||||
int getNumCPUs();
|
||||
json getCPU(int index);
|
||||
int getMasterCPU();
|
||||
int getPrimaryCPU();
|
||||
|
||||
int getNumGPUs();
|
||||
json getGPU(int index);
|
||||
int getMasterGPU();
|
||||
int getPrimaryGPU();
|
||||
|
||||
int getNumDisplays();
|
||||
json getDisplay(int index);
|
||||
int getMasterDisplay();
|
||||
int getPrimaryDisplay();
|
||||
|
||||
json getMemory();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace platform { namespace keys{
|
|||
extern const char* model;
|
||||
extern const char* clockSpeed;
|
||||
extern const char* numCores;
|
||||
extern const char* isMaster;
|
||||
extern const char* isPrimary;
|
||||
}
|
||||
namespace gpu {
|
||||
extern const char* vendor;
|
||||
|
@ -32,7 +32,7 @@ namespace platform { namespace keys{
|
|||
extern const char* videoMemory;
|
||||
extern const char* driver;
|
||||
extern const char* displays;
|
||||
extern const char* isMaster;
|
||||
extern const char* isPrimary;
|
||||
}
|
||||
namespace graphicsAPI {
|
||||
extern const char* name;
|
||||
|
@ -90,7 +90,7 @@ namespace platform { namespace keys{
|
|||
extern const char* modeRefreshrate;
|
||||
extern const char* modeWidth;
|
||||
extern const char* modeHeight;
|
||||
extern const char* isMaster;
|
||||
extern const char* isPrimary;
|
||||
}
|
||||
namespace memory {
|
||||
extern const char* memTotal;
|
||||
|
|
|
@ -32,9 +32,9 @@ Profiler::Tier Profiler::profilePlatform() {
|
|||
return platformTier;
|
||||
}
|
||||
|
||||
// Not filtered yet, let s try to make sense of the master cpu and master gpu info
|
||||
auto cpuInfo = platform::getCPU(platform::getMasterCPU());
|
||||
auto gpuInfo = platform::getGPU(platform::getMasterGPU());
|
||||
// Not filtered yet, let's try to make sense of the primary cpu and primary gpu info
|
||||
auto cpuInfo = platform::getCPU(platform::getPrimaryCPU());
|
||||
auto gpuInfo = platform::getGPU(platform::getPrimaryGPU());
|
||||
if (filterOnProcessors(computerInfo, cpuInfo, gpuInfo, platformTier)) {
|
||||
return platformTier;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ bool filterOnComputerMACOS(const platform::json& computer, Profiler::Tier& tier)
|
|||
// The simple rule for mac is
|
||||
// if it s an intel gpu then LOW
|
||||
// else go mid
|
||||
auto gpu = platform::getGPU(platform::getMasterGPU());
|
||||
auto gpu = platform::getGPU(platform::getPrimaryGPU());
|
||||
if (gpu.count(keys::gpu::vendor)) {
|
||||
std::string gpuVendor = gpu[keys::gpu::vendor].get<std::string>();
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ void MACOSInstance::enumerateGpusAndDisplays() {
|
|||
auto displaySizeHeightInches = displaySize.height * MM_TO_IN;
|
||||
|
||||
auto displayBounds = CGDisplayBounds(displayID);
|
||||
auto displayMaster =CGDisplayIsMain(displayID);
|
||||
auto displayPrimary =CGDisplayIsMain(displayID);
|
||||
|
||||
auto displayUnit =CGDisplayUnitNumber(displayID);
|
||||
auto displayModel =CGDisplayModelNumber(displayID);
|
||||
|
@ -112,8 +112,8 @@ void MACOSInstance::enumerateGpusAndDisplays() {
|
|||
// refreshrate
|
||||
display[keys::display::modeRefreshrate] = displayRefreshrate;
|
||||
|
||||
// Master display ?
|
||||
display[keys::display::isMaster] = (displayMaster ? true : false);
|
||||
// Primary display ?
|
||||
display[keys::display::isPrimary] = (displayPrimary ? true : false);
|
||||
|
||||
// Macos specific
|
||||
display["macos_unit"] = displayUnit;
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace platform { namespace keys {
|
|||
* @property {string} vendor - The CPU vendor (e.g., <code>"Intel"</code> or <code>"AMD"</code>).
|
||||
* @property {string} model - The CPU model.
|
||||
* @property {number} numCores - The number of logical cores.
|
||||
* @property {boolean} isMaster - <code>true</code> if the CPU is the "master" or primary CPU, <code>false</code> or
|
||||
* @property {boolean} isPrimary - <code>true</code> if the CPU is the primary CPU, <code>false</code> or
|
||||
* <code>undefined</code> if it isn't.
|
||||
*/
|
||||
namespace cpu {
|
||||
|
@ -41,7 +41,7 @@ namespace platform { namespace keys {
|
|||
const char* model = "model";
|
||||
const char* clockSpeed = "clockSpeed"; // FIXME: Not used.
|
||||
const char* numCores = "numCores";
|
||||
const char* isMaster = "isMaster";
|
||||
const char* isPrimary = "isPrimary";
|
||||
}
|
||||
|
||||
/*@jsdoc
|
||||
|
@ -53,7 +53,7 @@ namespace platform { namespace keys {
|
|||
* @property {number} videoMemory - The size of the GPU's video memory, in MB.
|
||||
* @property {number[]} displays - The index numbers of the displays currently being driven by the GPU. An empty array if
|
||||
* the GPU is currently not driving any displays.
|
||||
* @property {boolean} isMaster - <code>true</code> if the GPU is the "master" or primary GPU, <code>false</code> or
|
||||
* @property {boolean} isPrimary - <code>true</code> if the GPU is the primary GPU, <code>false</code> or
|
||||
* <code>undefined</code> if it isn't.
|
||||
*/
|
||||
namespace gpu {
|
||||
|
@ -66,7 +66,7 @@ namespace platform { namespace keys {
|
|||
const char* videoMemory = "videoMemory";
|
||||
const char* driver = "driver";
|
||||
const char* displays = "displays";
|
||||
const char* isMaster = "isMaster";
|
||||
const char* isPrimary = "isPrimary";
|
||||
}
|
||||
|
||||
/*@jsdoc
|
||||
|
@ -175,7 +175,7 @@ namespace platform { namespace keys {
|
|||
* @property {number} modeRefreshrate - The refresh rate of the current display mode, in Hz.
|
||||
* @property {number} modeWidth - The width of the current display mode, in pixels.
|
||||
* @property {number} modeHeight - The height of the current display mode, in pixels.
|
||||
* @property {boolean} isMaster - <code>true</code> if the GPU is the "master" or primary display, <code>false</code> or
|
||||
* @property {boolean} isPrimary - <code>true</code> if the GPU is the primary display, <code>false</code> or
|
||||
* <code>undefined</code> if it isn't.
|
||||
*/
|
||||
namespace display {
|
||||
|
@ -193,7 +193,7 @@ namespace platform { namespace keys {
|
|||
const char* modeRefreshrate = "modeRefreshrate";
|
||||
const char* modeWidth = "modeWidth";
|
||||
const char* modeHeight = "modeHeight";
|
||||
const char* isMaster = "isMaster";
|
||||
const char* isPrimary = "isPrimary";
|
||||
}
|
||||
|
||||
/*@jsdoc
|
||||
|
@ -300,8 +300,8 @@ json platform::getCPU(int index) {
|
|||
return _instance->getCPU(index);
|
||||
}
|
||||
|
||||
int platform::getMasterCPU() {
|
||||
return _instance->getMasterCPU();
|
||||
int platform::getPrimaryCPU() {
|
||||
return _instance->getPrimaryCPU();
|
||||
}
|
||||
|
||||
int platform::getNumGPUs() {
|
||||
|
@ -312,8 +312,8 @@ json platform::getGPU(int index) {
|
|||
return _instance->getGPU(index);
|
||||
}
|
||||
|
||||
int platform::getMasterGPU() {
|
||||
return _instance->getMasterGPU();
|
||||
int platform::getPrimaryGPU() {
|
||||
return _instance->getPrimaryGPU();
|
||||
}
|
||||
|
||||
int platform::getNumDisplays() {
|
||||
|
@ -324,8 +324,8 @@ json platform::getDisplay(int index) {
|
|||
return _instance->getDisplay(index);
|
||||
}
|
||||
|
||||
int platform::getMasterDisplay() {
|
||||
return _instance->getMasterDisplay();
|
||||
int platform::getPrimaryDisplay() {
|
||||
return _instance->getPrimaryDisplay();
|
||||
}
|
||||
|
||||
json platform::getMemory() {
|
||||
|
|
|
@ -41,8 +41,8 @@ bool Instance::enumeratePlatform() {
|
|||
enumerateNics();
|
||||
enumerateGraphicsApis();
|
||||
|
||||
// eval the master index for each platform scopes
|
||||
updateMasterIndices();
|
||||
// eval the primary index for each platform scopes
|
||||
updatePrimaryIndices();
|
||||
|
||||
// And profile the platform and put the tier in "computer"
|
||||
_computer[keys::computer::profileTier] = Profiler::TierNames[Profiler::profilePlatform()];
|
||||
|
@ -50,54 +50,54 @@ bool Instance::enumeratePlatform() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Instance::updateMasterIndices() {
|
||||
void Instance::updatePrimaryIndices() {
|
||||
// We assume a single CPU at the moment:
|
||||
{
|
||||
if (!_cpus.empty()) {
|
||||
_masterCPU = 0;
|
||||
_cpus[0][keys::cpu::isMaster] = true;
|
||||
_primaryCPU = 0;
|
||||
_cpus[0][keys::cpu::isPrimary] = true;
|
||||
} else {
|
||||
_masterCPU = NOT_FOUND;
|
||||
_primaryCPU = NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the displays list
|
||||
{
|
||||
_masterDisplay = NOT_FOUND;
|
||||
_primaryDisplay = NOT_FOUND;
|
||||
for (int i = 0; i < (int) _displays.size(); ++i) {
|
||||
const auto& display = _displays[i];
|
||||
if (display.count(keys::display::isMaster)) {
|
||||
if (display[keys::display::isMaster].get<bool>()) {
|
||||
_masterDisplay = i;
|
||||
if (display.count(keys::display::isPrimary)) {
|
||||
if (display[keys::display::isPrimary].get<bool>()) {
|
||||
_primaryDisplay = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NO master display found, return the first one or NOT_FOUND if no display
|
||||
if (_masterDisplay == NOT_FOUND) {
|
||||
// NO primary display found, return the first one or NOT_FOUND if no display
|
||||
if (_primaryDisplay == NOT_FOUND) {
|
||||
if (!_displays.empty()) {
|
||||
_masterDisplay = 0;
|
||||
_displays[0][keys::display::isMaster] = true;
|
||||
_primaryDisplay = 0;
|
||||
_displays[0][keys::display::isPrimary] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From the master display decide the master gpu
|
||||
// From the primary display decide the primary gpu
|
||||
{
|
||||
_masterGPU = NOT_FOUND;
|
||||
if (_masterDisplay != NOT_FOUND) {
|
||||
const auto& display = _displays[_masterDisplay];
|
||||
// FInd the GPU index of the master display
|
||||
_primaryGPU = NOT_FOUND;
|
||||
if (_primaryDisplay != NOT_FOUND) {
|
||||
const auto& display = _displays[_primaryDisplay];
|
||||
// FInd the GPU index of the primary display
|
||||
if (display.count(keys::display::gpu)) {
|
||||
_masterGPU = display[keys::display::gpu];
|
||||
_gpus[_masterGPU][keys::gpu::isMaster] = true;
|
||||
_primaryGPU = display[keys::display::gpu];
|
||||
_gpus[_primaryGPU][keys::gpu::isPrimary] = true;
|
||||
}
|
||||
}
|
||||
// NO master GPU found from master display, bummer, return the first one or NOT_FOUND if no display
|
||||
if (_masterGPU == NOT_FOUND) {
|
||||
// NO primary GPU found from primary display, bummer, return the first one or NOT_FOUND if no display
|
||||
if (_primaryGPU == NOT_FOUND) {
|
||||
if (!_gpus.empty()) {
|
||||
_masterGPU = 0;
|
||||
_gpus[0][keys::gpu::isMaster] = true;
|
||||
_primaryGPU = 0;
|
||||
_gpus[0][keys::gpu::isPrimary] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,15 +23,15 @@ public:
|
|||
|
||||
int getNumCPUs() { return (int)_cpus.size(); }
|
||||
json getCPU(int index);
|
||||
int getMasterCPU() const { return _masterCPU; }
|
||||
int getPrimaryCPU() const { return _primaryCPU; }
|
||||
|
||||
int getNumGPUs() { return (int)_gpus.size(); }
|
||||
json getGPU(int index);
|
||||
int getMasterGPU() const { return _masterGPU; }
|
||||
int getPrimaryGPU() const { return _primaryGPU; }
|
||||
|
||||
int getNumDisplays() { return (int)_displays.size(); }
|
||||
json getDisplay(int index);
|
||||
int getMasterDisplay() const { return _masterDisplay; }
|
||||
int getPrimaryDisplay() const { return _primaryDisplay; }
|
||||
|
||||
json getMemory() { return _memory; }
|
||||
|
||||
|
@ -62,12 +62,12 @@ protected:
|
|||
json _memory;
|
||||
json _computer;
|
||||
|
||||
int _masterCPU{ -1 };
|
||||
int _masterGPU{ -1 };
|
||||
int _masterDisplay{ -1 };
|
||||
int _primaryCPU{ -1 };
|
||||
int _primaryGPU{ -1 };
|
||||
int _primaryDisplay{ -1 };
|
||||
|
||||
// Traverse the cpus, gpus and displays to update the "master" index in each domain
|
||||
void updateMasterIndices();
|
||||
// Traverse the cpus, gpus and displays to update the "primary" index in each domain
|
||||
void updatePrimaryIndices();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -167,8 +167,8 @@ void WINInstance::enumerateGpusAndDisplays() {
|
|||
// refreshrate
|
||||
display[keys::display::modeRefreshrate] = devMode.dmDisplayFrequency;;
|
||||
|
||||
// Master display ?
|
||||
display[keys::display::isMaster] = (bool) (monitorInfo.dwFlags & MONITORINFOF_PRIMARY);
|
||||
// Primary display ?
|
||||
display[keys::display::isPrimary] = (bool) (monitorInfo.dwFlags & MONITORINFOF_PRIMARY);
|
||||
|
||||
// Add the display index to the list of displays of the gpu
|
||||
displayIndices.push_back((int) _displays.size());
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
Q_LOGGING_CATEGORY(proceduralLog, "hifi.gpu.procedural")
|
||||
|
||||
bool Procedural::enableProceduralShaders = false;
|
||||
|
||||
// User-data parsing constants
|
||||
static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity";
|
||||
static const QString VERTEX_URL_KEY = "vertexShaderURL";
|
||||
|
@ -377,6 +379,27 @@ void Procedural::prepare(gpu::Batch& batch,
|
|||
|
||||
_proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState);
|
||||
|
||||
// Error fallback: pink checkerboard
|
||||
if (_errorFallbackFragmentSource.isEmpty()) {
|
||||
QFile file(_errorFallbackFragmentPath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
_errorFallbackFragmentSource = QTextStream(&file).readAll();
|
||||
}
|
||||
vertexSource.replacements.erase(PROCEDURAL_BLOCK);
|
||||
fragmentSource.replacements[PROCEDURAL_BLOCK] = _errorFallbackFragmentSource.toStdString();
|
||||
gpu::ShaderPointer errorVertexShader = gpu::Shader::createVertex(vertexSource);
|
||||
gpu::ShaderPointer errorFragmentShader = gpu::Shader::createPixel(fragmentSource);
|
||||
gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(errorVertexShader, errorFragmentShader);
|
||||
_errorPipelines[key] = gpu::Pipeline::create(errorProgram, _opaqueState);
|
||||
|
||||
// Disabled fallback: nothing
|
||||
vertexSource.replacements.erase(PROCEDURAL_BLOCK);
|
||||
fragmentSource.replacements.erase(PROCEDURAL_BLOCK);
|
||||
gpu::ShaderPointer disabledVertexShader = gpu::Shader::createVertex(vertexSource);
|
||||
gpu::ShaderPointer disabledFragmentShader = gpu::Shader::createPixel(fragmentSource);
|
||||
gpu::ShaderPointer disabledProgram = gpu::Shader::createProgram(disabledVertexShader, disabledFragmentShader);
|
||||
_disabledPipelines[key] = gpu::Pipeline::create(disabledProgram, _opaqueState);
|
||||
|
||||
_lastCompile = usecTimestampNow();
|
||||
if (_firstCompile == 0) {
|
||||
_firstCompile = _lastCompile;
|
||||
|
@ -385,8 +408,15 @@ void Procedural::prepare(gpu::Batch& batch,
|
|||
recompiledShader = true;
|
||||
}
|
||||
|
||||
gpu::PipelinePointer finalPipeline = recompiledShader ? _proceduralPipelines[key] : pipeline->second;
|
||||
if (!enableProceduralShaders) {
|
||||
finalPipeline = _disabledPipelines[key];
|
||||
} else if (!finalPipeline || finalPipeline->getProgram()->compilationHasFailed()) {
|
||||
finalPipeline = _errorPipelines[key];
|
||||
}
|
||||
|
||||
// FIXME: need to handle forward rendering
|
||||
batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second);
|
||||
batch.setPipeline(finalPipeline);
|
||||
|
||||
bool recreateUniforms = _shaderDirty || _uniformsDirty || recompiledShader || _prevKey != key;
|
||||
if (recreateUniforms) {
|
||||
|
@ -533,4 +563,6 @@ void graphics::ProceduralMaterial::initializeProcedural() {
|
|||
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
|
||||
_procedural._opaqueFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural);
|
||||
_procedural._transparentFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural_translucent);
|
||||
|
||||
_procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorShader.frag").path();
|
||||
}
|
|
@ -124,12 +124,16 @@ public:
|
|||
gpu::Shader::Source _opaqueFragmentSource;
|
||||
gpu::Shader::Source _transparentFragmentSource;
|
||||
|
||||
QString _errorFallbackFragmentPath;
|
||||
|
||||
gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
|
||||
gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
|
||||
|
||||
static std::function<void(gpu::StatePointer)> opaqueStencil;
|
||||
static std::function<void(gpu::StatePointer)> transparentStencil;
|
||||
|
||||
static bool enableProceduralShaders;
|
||||
|
||||
protected:
|
||||
// DO NOT TOUCH
|
||||
// We have to pack these in a particular way to match the ProceduralCommon.slh
|
||||
|
@ -176,11 +180,15 @@ protected:
|
|||
bool _shaderDirty { true };
|
||||
bool _uniformsDirty { true };
|
||||
|
||||
QString _errorFallbackFragmentSource;
|
||||
|
||||
// Rendering objects
|
||||
UniformLambdas _uniforms;
|
||||
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
|
||||
|
||||
std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _proceduralPipelines;
|
||||
std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _errorPipelines;
|
||||
std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _disabledPipelines;
|
||||
|
||||
StandardInputs _standardInputs;
|
||||
gpu::BufferPointer _standardInputsBuffer;
|
||||
|
|
|
@ -22,6 +22,8 @@ ProceduralSkybox::ProceduralSkybox(uint64_t created) : graphics::Skybox(), _crea
|
|||
_procedural._vertexSource = shader::Source::get(shader::graphics::vertex::skybox);
|
||||
_procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox);
|
||||
|
||||
_procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorSkyboxShader.frag").path();
|
||||
|
||||
_procedural.setDoesFade(false);
|
||||
|
||||
// Adjust the pipeline state for background using the stencil test
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
bool ModelMeshPartPayload::enableMaterialProceduralShaders = false;
|
||||
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,
|
||||
const Transform& transform, const uint64_t& created) :
|
||||
_meshIndex(meshIndex),
|
||||
|
@ -345,9 +343,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
if (_shapeKey.hasOwnPipeline()) {
|
||||
if (!(enableMaterialProceduralShaders)) {
|
||||
return;
|
||||
}
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
|
||||
auto& schema = _drawMaterials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||
|
|
|
@ -68,8 +68,6 @@ public:
|
|||
|
||||
void setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes);
|
||||
|
||||
static bool enableMaterialProceduralShaders;
|
||||
|
||||
private:
|
||||
void initCache(const ModelPointer& model, int shapeID);
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ void Transaction::clear() {
|
|||
|
||||
|
||||
Scene::Scene(glm::vec3 origin, float size) :
|
||||
_masterSpatialTree(origin, size)
|
||||
_primarySpatialTree(origin, size)
|
||||
{
|
||||
_items.push_back(Item()); // add the itemID #0 to nothing
|
||||
}
|
||||
|
@ -306,10 +306,10 @@ void Scene::resetItems(const Transaction::Resets& transactions) {
|
|||
// Update the item's container
|
||||
assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
|
||||
if (newKey.isSpatial()) {
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), itemId, newKey);
|
||||
auto newCell = _primarySpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), itemId, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
} else {
|
||||
_masterNonspatialSet.insert(itemId);
|
||||
_primaryNonspatialSet.insert(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,9 +323,9 @@ void Scene::removeItems(const Transaction::Removes& transactions) {
|
|||
|
||||
// Remove the item
|
||||
if (oldKey.isSpatial()) {
|
||||
_masterSpatialTree.removeItem(oldCell, oldKey, removedID);
|
||||
_primarySpatialTree.removeItem(oldCell, oldKey, removedID);
|
||||
} else {
|
||||
_masterNonspatialSet.erase(removedID);
|
||||
_primaryNonspatialSet.erase(removedID);
|
||||
}
|
||||
|
||||
// Remove the transition to prevent updating it for nothing
|
||||
|
@ -362,20 +362,20 @@ void Scene::updateItems(const Transaction::Updates& transactions) {
|
|||
// Update the item's container
|
||||
if (oldKey.isSpatial() == newKey.isSpatial()) {
|
||||
if (newKey.isSpatial()) {
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
auto newCell = _primarySpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
}
|
||||
} else {
|
||||
if (newKey.isSpatial()) {
|
||||
_masterNonspatialSet.erase(updateID);
|
||||
_primaryNonspatialSet.erase(updateID);
|
||||
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
auto newCell = _primarySpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
} else {
|
||||
_masterSpatialTree.removeItem(oldCell, oldKey, updateID);
|
||||
_primarySpatialTree.removeItem(oldCell, oldKey, updateID);
|
||||
item.resetCell();
|
||||
|
||||
_masterNonspatialSet.insert(updateID);
|
||||
_primaryNonspatialSet.insert(updateID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,10 +185,10 @@ public:
|
|||
const Item getItemSafe(const ItemID& id) const { if (isAllocatedID(id)) { return _items[id]; } else { return Item(); } }
|
||||
|
||||
// Access the spatialized items
|
||||
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
|
||||
const ItemSpatialTree& getSpatialTree() const { return _primarySpatialTree; }
|
||||
|
||||
// Access non-spatialized items (layered objects, backgrounds)
|
||||
const ItemIDSet& getNonspatialSet() const { return _masterNonspatialSet; }
|
||||
const ItemIDSet& getNonspatialSet() const { return _primaryNonspatialSet; }
|
||||
|
||||
// Access a particular Stage (empty if doesn't exist)
|
||||
// Thread safe
|
||||
|
@ -226,8 +226,8 @@ protected:
|
|||
// database of items is protected for editing by a mutex
|
||||
std::mutex _itemsMutex;
|
||||
Item::Vector _items;
|
||||
ItemSpatialTree _masterSpatialTree;
|
||||
ItemIDSet _masterNonspatialSet;
|
||||
ItemSpatialTree _primarySpatialTree;
|
||||
ItemIDSet _primaryNonspatialSet;
|
||||
|
||||
void resetItems(const Transaction::Resets& transactions);
|
||||
void resetTransitionFinishedOperator(const Transaction::TransitionFinishedOperators& transactions);
|
||||
|
|
|
@ -19,21 +19,21 @@ void ScriptGatekeeper::initialize() {
|
|||
return;
|
||||
}
|
||||
|
||||
QVariant rawCurrentWhitelistValues = Setting::Handle<QVariant>(SCRIPT_WHITELIST_ENTRIES_KEY).get();
|
||||
QString settingsSafeValues = rawCurrentWhitelistValues.toString();
|
||||
QVariant rawCurrentAllowlistValues = Setting::Handle<QVariant>(SCRIPT_ALLOWLIST_ENTRIES_KEY).get();
|
||||
QString settingsSafeValues = rawCurrentAllowlistValues.toString();
|
||||
|
||||
Setting::Handle<bool> whitelistEnabled { SCRIPT_WHITELIST_ENABLED_KEY, false };
|
||||
Setting::Handle<bool> allowlistEnabled { SCRIPT_ALLOWLIST_ENABLED_KEY, false };
|
||||
Setting::Handle<bool> isFirstRun { Settings::firstRun, true };
|
||||
|
||||
QString preloadedVal = BuildInfo::PRELOADED_SCRIPT_WHITELIST;
|
||||
QString preloadedVal = BuildInfo::PRELOADED_SCRIPT_ALLOWLIST;
|
||||
|
||||
if (settingsSafeValues.isEmpty() && !preloadedVal.isEmpty() && isFirstRun.get()) {
|
||||
// We assume that the whitelist should be enabled if a preloaded whitelist is attached, so we activate it if it's not already active.
|
||||
if (!whitelistEnabled.get()) {
|
||||
whitelistEnabled.set(true);
|
||||
// We assume that the allowlist should be enabled if a preloaded allowlist is attached, so we activate it if it's not already active.
|
||||
if (!allowlistEnabled.get()) {
|
||||
allowlistEnabled.set(true);
|
||||
}
|
||||
|
||||
Setting::Handle<QVariant>(SCRIPT_WHITELIST_ENTRIES_KEY).set(preloadedVal);
|
||||
Setting::Handle<QVariant>(SCRIPT_ALLOWLIST_ENTRIES_KEY).set(preloadedVal);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
/// Manages script whitelisting in a domain
|
||||
/// Manages script allowlisting in a domain
|
||||
class ScriptGatekeeper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
void initialize();
|
||||
|
||||
QString SCRIPT_WHITELIST_ENABLED_KEY{ "private/whitelistEnabled" };
|
||||
QString SCRIPT_WHITELIST_ENTRIES_KEY{ "private/settingsSafeURLS" };
|
||||
QString SCRIPT_ALLOWLIST_ENABLED_KEY{ "private/allowlistEnabled" };
|
||||
QString SCRIPT_ALLOWLIST_ENTRIES_KEY{ "private/settingsSafeURLS" };
|
||||
|
||||
private:
|
||||
bool _initialized { false };
|
||||
|
|
|
@ -2192,17 +2192,17 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
exception = testConstructor;
|
||||
}
|
||||
} else {
|
||||
// ENTITY SCRIPT WHITELIST STARTS HERE
|
||||
// ENTITY SCRIPT ALLOWLIST STARTS HERE
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
bool passList = false; // assume unsafe
|
||||
QString whitelistPrefix = "[WHITELIST ENTITY SCRIPTS]";
|
||||
QString allowlistPrefix = "[ALLOWLIST ENTITY SCRIPTS]";
|
||||
QList<QString> safeURLPrefixes = { "file:///", "atp:", "cache:" };
|
||||
safeURLPrefixes += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
safeURLPrefixes += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
|
||||
// Entity Script Whitelist toggle check.
|
||||
Setting::Handle<bool> whitelistEnabled {"private/whitelistEnabled", false };
|
||||
// Entity Script Allowlist toggle check.
|
||||
Setting::Handle<bool> allowlistEnabled {"private/allowlistEnabled", false };
|
||||
|
||||
if (!whitelistEnabled.get()) {
|
||||
if (!allowlistEnabled.get()) {
|
||||
passList = true;
|
||||
}
|
||||
|
||||
|
@ -2212,39 +2212,39 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
safeURLPrefixes += settingsSafeURLS;
|
||||
// END Pull SAFEURLS from the Interface.JSON settings.
|
||||
|
||||
// Get current domain whitelist bypass, in case an entire domain is whitelisted.
|
||||
// Get current domain allowlist bypass, in case an entire domain is allowlisted.
|
||||
QString currentDomain = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
||||
|
||||
QString domainSafeIP = nodeList->getDomainHandler().getHostname();
|
||||
QString domainSafeURL = URL_SCHEME_OVERTE + "://" + currentDomain;
|
||||
for (const auto& str : safeURLPrefixes) {
|
||||
if (domainSafeURL.startsWith(str) || domainSafeIP.startsWith(str)) {
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Whitelist Bypassed, entire domain is whitelisted. Current Domain Host: "
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Allowlist Bypassed, entire domain is allowlisted. Current Domain Host: "
|
||||
<< nodeList->getDomainHandler().getHostname()
|
||||
<< "Current Domain: " << currentDomain;
|
||||
passList = true;
|
||||
}
|
||||
}
|
||||
// END bypass whitelist based on current domain.
|
||||
// END bypass allowlist based on current domain.
|
||||
|
||||
// Start processing scripts through the whitelist.
|
||||
if (ScriptManager::getContext() == "entity_server") { // If running on the server, do not engage whitelist.
|
||||
// Start processing scripts through the allowlist.
|
||||
if (ScriptManager::getContext() == "entity_server") { // If running on the server, do not engage allowlist.
|
||||
passList = true;
|
||||
} else if (!passList) { // If waved through, do not engage whitelist.
|
||||
} else if (!passList) { // If waved through, do not engage allowlist.
|
||||
for (const auto& str : safeURLPrefixes) {
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Script URL: " << scriptOrURL << "TESTING AGAINST" << str << "RESULTS IN"
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Script URL: " << scriptOrURL << "TESTING AGAINST" << str << "RESULTS IN"
|
||||
<< scriptOrURL.startsWith(str);
|
||||
if (!str.isEmpty() && scriptOrURL.startsWith(str)) {
|
||||
passList = true;
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Script approved.";
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Script approved.";
|
||||
break; // Bail early since we found a match.
|
||||
}
|
||||
}
|
||||
}
|
||||
// END processing of scripts through the whitelist.
|
||||
// END processing of scripts through the allowlist.
|
||||
|
||||
if (!passList) { // If the entity failed to pass for any reason, it's blocked and an error is thrown.
|
||||
qCDebug(scriptengine) << whitelistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
qCDebug(scriptengine) << allowlistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
exception = _engine->makeError(_engine->newValue("UNSAFE_ENTITY_SCRIPTS == 0"));
|
||||
} else {
|
||||
QTimer timeout;
|
||||
|
@ -2267,7 +2267,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
exception = testConstructor;
|
||||
}
|
||||
}
|
||||
// ENTITY SCRIPT WHITELIST ENDS HERE, uncomment below for original full disabling.
|
||||
// ENTITY SCRIPT ALLOWLIST ENDS HERE, uncomment below for original full disabling.
|
||||
|
||||
// qCDebug(scriptengine) << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
// exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0");
|
||||
|
@ -2303,17 +2303,17 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
return; // done processing script
|
||||
}*/
|
||||
|
||||
// ENTITY SCRIPT WHITELIST STARTS HERE
|
||||
// ENTITY SCRIPT ALLOWLIST STARTS HERE
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
bool passList = false; // assume unsafe
|
||||
QString whitelistPrefix = "[WHITELIST ENTITY SCRIPTS]";
|
||||
QString allowlistPrefix = "[ALLOWLIST ENTITY SCRIPTS]";
|
||||
QList<QString> safeURLPrefixes = { "file:///", "atp:", "cache:" };
|
||||
safeURLPrefixes += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
safeURLPrefixes += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts);
|
||||
|
||||
// Entity Script Whitelist toggle check.
|
||||
Setting::Handle<bool> whitelistEnabled {"private/whitelistEnabled", false };
|
||||
// Entity Script Allowlist toggle check.
|
||||
Setting::Handle<bool> allowlistEnabled {"private/allowlistEnabled", false };
|
||||
|
||||
if (!whitelistEnabled.get()) {
|
||||
if (!allowlistEnabled.get()) {
|
||||
passList = true;
|
||||
}
|
||||
|
||||
|
@ -2323,40 +2323,40 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
safeURLPrefixes += settingsSafeURLS;
|
||||
// END Pull SAFEURLS from the Interface.JSON settings.
|
||||
|
||||
// Get current domain whitelist bypass, in case an entire domain is whitelisted.
|
||||
// Get current domain allowlist bypass, in case an entire domain is allowlisted.
|
||||
QString currentDomain = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
||||
|
||||
QString domainSafeIP = nodeList->getDomainHandler().getHostname();
|
||||
QString domainSafeURL = URL_SCHEME_OVERTE + "://" + currentDomain;
|
||||
for (const auto& str : safeURLPrefixes) {
|
||||
if (domainSafeURL.startsWith(str) || domainSafeIP.startsWith(str)) {
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Whitelist Bypassed, entire domain is whitelisted. Current Domain Host: "
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Allowlist Bypassed, entire domain is allowlisted. Current Domain Host: "
|
||||
<< nodeList->getDomainHandler().getHostname()
|
||||
<< "Current Domain: " << currentDomain;
|
||||
passList = true;
|
||||
}
|
||||
}
|
||||
// END bypass whitelist based on current domain.
|
||||
// END bypass allowlist based on current domain.
|
||||
|
||||
// Start processing scripts through the whitelist.
|
||||
if (ScriptManager::getContext() == "entity_server") { // If running on the server, do not engage whitelist.
|
||||
// Start processing scripts through the allowlist.
|
||||
if (ScriptManager::getContext() == "entity_server") { // If running on the server, do not engage allowlist.
|
||||
passList = true;
|
||||
} else if (!passList) { // If waved through, do not engage whitelist.
|
||||
} else if (!passList) { // If waved through, do not engage allowlist.
|
||||
for (const auto& str : safeURLPrefixes) {
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Script URL: " << scriptOrURL << "TESTING AGAINST" << str << "RESULTS IN"
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Script URL: " << scriptOrURL << "TESTING AGAINST" << str << "RESULTS IN"
|
||||
<< scriptOrURL.startsWith(str);
|
||||
if (!str.isEmpty() && scriptOrURL.startsWith(str)) {
|
||||
passList = true;
|
||||
qCDebug(scriptengine) << whitelistPrefix << "Script approved.";
|
||||
qCDebug(scriptengine) << allowlistPrefix << "Script approved.";
|
||||
break; // Bail early since we found a match.
|
||||
}
|
||||
}
|
||||
}
|
||||
// END processing of scripts through the whitelist.
|
||||
// END processing of scripts through the allowlist.
|
||||
|
||||
ScriptValue exception;
|
||||
if (!passList) { // If the entity failed to pass for any reason, it's blocked and an error is thrown.
|
||||
qCDebug(scriptengine) << whitelistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
qCDebug(scriptengine) << allowlistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
exception = _engine->makeError(_engine->newValue("UNSAFE_ENTITY_SCRIPTS == 0"));
|
||||
}
|
||||
|
||||
|
@ -2369,7 +2369,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
|
|||
emit unhandledException(scriptRuntimeException);
|
||||
return;
|
||||
}
|
||||
// ENTITY SCRIPT WHITELIST ENDS HERE, uncomment below for original full disabling.
|
||||
// ENTITY SCRIPT ALLOWLIST ENDS HERE, uncomment below for original full disabling.
|
||||
|
||||
// qCDebug(scriptengine) << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||
// exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0");
|
||||
|
|
|
@ -110,17 +110,17 @@ public slots:
|
|||
bool getPersonalMuteStatus(const QUuid& nodeID);
|
||||
|
||||
/*@jsdoc
|
||||
* Sets an avatar's gain (volume) for you and you only, or sets the master gain.
|
||||
* Sets an avatar's gain (volume) for you and you only, or sets the primary gain.
|
||||
* @function Users.setAvatarGain
|
||||
* @param {Uuid} nodeID - The session ID of the avatar to set the gain for, or <code>null</code> to set the master gain.
|
||||
* @param {Uuid} nodeID - The session ID of the avatar to set the gain for, or <code>null</code> to set the primary gain.
|
||||
* @param {number} gain - The gain to set, in dB.
|
||||
*/
|
||||
void setAvatarGain(const QUuid& nodeID, float gain);
|
||||
|
||||
/*@jsdoc
|
||||
* Gets an avatar's gain (volume) for you and you only, or gets the master gain.
|
||||
* Gets an avatar's gain (volume) for you and you only, or gets the primary gain.
|
||||
* @function Users.getAvatarGain
|
||||
* @param {Uuid} nodeID - The session ID of the avatar to get the gain for, or <code>null</code> to get the master gain.
|
||||
* @param {Uuid} nodeID - The session ID of the avatar to get the gain for, or <code>null</code> to get the primary gain.
|
||||
* @returns {number} The gain, in dB.
|
||||
*/
|
||||
float getAvatarGain(const QUuid& nodeID);
|
||||
|
|
|
@ -854,11 +854,11 @@ void printSystemInformation() {
|
|||
|
||||
qCDebug(shared) << "Environment Variables";
|
||||
// List of env variables to include in the log. For privacy reasons we don't send all env variables.
|
||||
const QStringList envWhitelist = {
|
||||
const QStringList envAllowlist = {
|
||||
"QTWEBENGINE_REMOTE_DEBUGGING"
|
||||
};
|
||||
auto envVariables = QProcessEnvironment::systemEnvironment();
|
||||
for (auto& env : envWhitelist)
|
||||
for (auto& env : envAllowlist)
|
||||
{
|
||||
qCDebug(shared).noquote().nospace() << "\t" <<
|
||||
(envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND");
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifdef OVERTE_WARNINGS_WHITELIST_GCC
|
||||
#ifdef OVERTE_WARNINGS_ALLOWLIST_GCC
|
||||
|
||||
#define OVERTE_IGNORE_DEPRECATED_BEGIN \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
|
@ -27,7 +27,7 @@
|
|||
|
||||
#define OVERTE_IGNORE_DEPRECATED_END _Pragma("GCC diagnostic pop")
|
||||
|
||||
#elif OVERTE_WARNINGS_WHITELIST_CLANG
|
||||
#elif OVERTE_WARNINGS_ALLOWLIST_CLANG
|
||||
|
||||
#define OVERTE_IGNORE_DEPRECATED_BEGIN \
|
||||
_Pragma("clang diagnostic push") \
|
||||
|
@ -35,7 +35,7 @@
|
|||
|
||||
#define OVERTE_IGNORE_DEPRECATED_END _Pragma("clang diagnostic pop")
|
||||
|
||||
#elif OVERTE_WARNINGS_WHITELIST_MSVC
|
||||
#elif OVERTE_WARNINGS_ALLOWLIST_MSVC
|
||||
|
||||
#define OVERTE_IGNORE_DEPRECATED_BEGIN \
|
||||
_Pragma("warning(push)") \
|
||||
|
|
|
@ -63,11 +63,11 @@
|
|||
|
||||
namespace hifi { namespace qml { namespace offscreen {
|
||||
|
||||
class OffscreenQmlWhitelist : public Dependency, private ReadWriteLockable {
|
||||
class OffscreenQmlAllowlist : public Dependency, private ReadWriteLockable {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback) {
|
||||
void addAllowlistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback) {
|
||||
withWriteLock([&] {
|
||||
for (auto url : urls) {
|
||||
if (url.isRelative()) {
|
||||
|
@ -93,11 +93,11 @@ private:
|
|||
QHash<QUrl, QList<QmlContextCallback>> _callbacks;
|
||||
};
|
||||
|
||||
QSharedPointer<OffscreenQmlWhitelist> getQmlWhitelist() {
|
||||
QSharedPointer<OffscreenQmlAllowlist> getQmlAllowlist() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] { DependencyManager::set<OffscreenQmlWhitelist>(); });
|
||||
std::call_once(once, [&] { DependencyManager::set<OffscreenQmlAllowlist>(); });
|
||||
|
||||
return DependencyManager::get<OffscreenQmlWhitelist>();
|
||||
return DependencyManager::get<OffscreenQmlAllowlist>();
|
||||
}
|
||||
|
||||
// Class to handle changing QML audio output device using another thread
|
||||
|
@ -292,9 +292,9 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
|
|||
engine->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list<QUrl>& urls,
|
||||
void OffscreenQmlSurface::addAllowlistContextHandler(const std::initializer_list<QUrl>& urls,
|
||||
const QmlContextCallback& callback) {
|
||||
getQmlWhitelist()->addWhitelistContextHandler(urls, callback);
|
||||
getQmlAllowlist()->addAllowlistContextHandler(urls, callback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::onRootContextCreated(QQmlContext* qmlContext) {
|
||||
|
@ -319,17 +319,17 @@ void OffscreenQmlSurface::onRootContextCreated(QQmlContext* qmlContext) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::applyWhiteList(const QUrl& url, QQmlContext* context) {
|
||||
QList<QmlContextCallback> callbacks = getQmlWhitelist()->getCallbacksForUrl(url);
|
||||
void OffscreenQmlSurface::applyAllowList(const QUrl& url, QQmlContext* context) {
|
||||
QList<QmlContextCallback> callbacks = getQmlAllowlist()->getCallbacksForUrl(url);
|
||||
for(const auto& callback : callbacks){
|
||||
callback(context);
|
||||
}
|
||||
}
|
||||
|
||||
QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext) {
|
||||
// Get any whitelist functionality
|
||||
QList<QmlContextCallback> callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource);
|
||||
// If we have whitelisted content, we must load a new context
|
||||
// Get any allowlist functionality
|
||||
QList<QmlContextCallback> callbacks = getQmlAllowlist()->getCallbacksForUrl(qmlSource);
|
||||
// If we have allowlisted content, we must load a new context
|
||||
forceNewContext |= !callbacks.empty();
|
||||
|
||||
QQmlContext* targetContext = Parent::contextForUrl(qmlSource, parent, forceNewContext);
|
||||
|
|
|
@ -28,9 +28,9 @@ class OffscreenQmlSurface : public hifi::qml::OffscreenSurface {
|
|||
public:
|
||||
~OffscreenQmlSurface();
|
||||
|
||||
static void addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback);
|
||||
static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); };
|
||||
static void applyWhiteList(const QUrl& url,QQmlContext* context);
|
||||
static void addAllowlistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback);
|
||||
static void addAllowlistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addAllowlistContextHandler({ { url } }, callback); };
|
||||
static void applyAllowList(const QUrl& url,QQmlContext* context);
|
||||
|
||||
bool isFocusText() const { return _focusText; }
|
||||
bool getCleaned() { return _isCleaned; }
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace {
|
|||
return false;
|
||||
}
|
||||
|
||||
// We can potentially add whitelisting logic or development environment variables that
|
||||
// We can potentially add allowlisting logic or development environment variables that
|
||||
// will allow people to override this setting on a per-client basis here.
|
||||
QString targetFilePath = QFileInfo(requestUrl.toLocalFile()).canonicalFilePath();
|
||||
|
||||
|
|
|
@ -487,13 +487,17 @@ Rectangle {
|
|||
var last_item_index = channel.count - 1;
|
||||
var last_item = channel.get(last_item_index);
|
||||
|
||||
if (last_message_user === username && elapsed_minutes < 1 && last_item){
|
||||
message = "<br>" + message
|
||||
last_item.text = last_item.text += "\n" + message;
|
||||
scrollToBottom()
|
||||
last_message_time = new Date();
|
||||
return;
|
||||
}
|
||||
// FIXME: When adding a new message this would check to see if we could append the incoming message
|
||||
// to the bottom of the last message. This current implimentation causes issues with scrollToBottom()
|
||||
// Specifically, scrolling to the bottom does not like image embeds.
|
||||
// This needs to be reworked entirely before it can be reimplimented
|
||||
// if (last_message_user === username && elapsed_minutes < 1 && last_item){
|
||||
// message = "<br>" + message
|
||||
// last_item.text = last_item.text += "\n" + message;
|
||||
// scrollToBottom()
|
||||
// last_message_time = new Date();
|
||||
// return;
|
||||
// }
|
||||
|
||||
last_message_user = username;
|
||||
last_message_time = new Date();
|
||||
|
@ -510,7 +514,7 @@ Rectangle {
|
|||
mess = mess.replace(arrow, "<");
|
||||
|
||||
var link = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
|
||||
mess = mess.replace(link, (match) => {return "<a onclick='Window.openUrl("+match+")' href='" + match + "'>" + match + "</a> <a onclick='Window.openUrl("+match+")'>🗗</a>"});
|
||||
mess = mess.replace(link, (match) => {return `<a style="color:#4EBAFD" onclick='Window.openUrl("+match+")' href='` + match + `'>` + match + `</a> <a onclick='Window.openUrl(`+match+`)'>🗗</a>`});
|
||||
|
||||
var newline = /\n/gi;
|
||||
mess = mess.replace(newline, "<br>");
|
||||
|
|
|
@ -37,7 +37,6 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
"system/inspect.js",
|
||||
"system/keyboardShortcuts/keyboardShortcuts.js",
|
||||
"system/onEscape.js",
|
||||
"system/onFirstRun.js",
|
||||
"system/places/places.js"
|
||||
//"developer/debugging/scriptMemoryReport.js"
|
||||
];
|
||||
|
|
|
@ -36,8 +36,8 @@ var pickID = Picks.createPick(PickType.Ray, {
|
|||
filter: PICK_FILTERS,
|
||||
enabled: true,
|
||||
});
|
||||
var blacklist = [ overlayID ]; // exclude hover text from ray pick results
|
||||
Picks.setIgnoreItems(pickID, blacklist);
|
||||
var blocklist = [ overlayID ]; // exclude hover text from ray pick results
|
||||
Picks.setIgnoreItems(pickID, blocklist);
|
||||
Script.scriptEnding.connect(function() {
|
||||
Picks.removePick(pickID);
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.veryhighVarianceCount = 0;
|
||||
this.orderedPluginNames = [];
|
||||
this.tabletID = null;
|
||||
this.blacklist = [];
|
||||
this.blocklist = [];
|
||||
this.pointerManager = new PointerManager();
|
||||
this.grabSphereOverlays = [null, null];
|
||||
this.targetIDs = {};
|
||||
|
@ -169,8 +169,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.setIgnorePointerItems = function() {
|
||||
if (HMD.tabletID && HMD.tabletID !== this.tabletID) {
|
||||
this.tabletID = HMD.tabletID;
|
||||
Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist);
|
||||
Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist);
|
||||
Pointers.setIgnoreItems(_this.leftPointer, _this.blocklist);
|
||||
Pointers.setIgnoreItems(_this.rightPointer, _this.blocklist);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -547,19 +547,19 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
};
|
||||
|
||||
this.leftBlacklistTabletIDs = [];
|
||||
this.rightBlacklistTabletIDs = [];
|
||||
this.leftBlocklistTabletIDs = [];
|
||||
this.rightBlocklistTabletIDs = [];
|
||||
|
||||
this.setLeftBlacklist = function () {
|
||||
Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat(_this.leftBlacklistTabletIDs));
|
||||
this.setLeftBlocklist = function () {
|
||||
Pointers.setIgnoreItems(_this.leftPointer, _this.blocklist.concat(_this.leftBlocklistTabletIDs));
|
||||
};
|
||||
this.setRightBlacklist = function () {
|
||||
Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat(_this.rightBlacklistTabletIDs));
|
||||
this.setRightBlocklist = function () {
|
||||
Pointers.setIgnoreItems(_this.rightPointer, _this.blocklist.concat(_this.rightBlocklistTabletIDs));
|
||||
};
|
||||
|
||||
this.setBlacklist = function() {
|
||||
_this.setLeftBlacklist();
|
||||
_this.setRightBlacklist();
|
||||
this.setBlocklist = function() {
|
||||
_this.setLeftBlocklist();
|
||||
_this.setRightBlocklist();
|
||||
};
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.controllerDispatcher";
|
||||
|
@ -634,34 +634,34 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
var message;
|
||||
if (sender === MyAvatar.sessionUUID) {
|
||||
try {
|
||||
if (channel === 'Hifi-Hand-RayPick-Blacklist') {
|
||||
if (channel === 'Hifi-Hand-RayPick-Blocklist') {
|
||||
message = JSON.parse(data);
|
||||
var action = message.action;
|
||||
var id = message.id;
|
||||
var index = _this.blacklist.indexOf(id);
|
||||
var index = _this.blocklist.indexOf(id);
|
||||
|
||||
if (action === 'add' && index === -1) {
|
||||
_this.blacklist.push(id);
|
||||
_this.setBlacklist();
|
||||
_this.blocklist.push(id);
|
||||
_this.setBlocklist();
|
||||
}
|
||||
|
||||
if (action === 'remove') {
|
||||
if (index > -1) {
|
||||
_this.blacklist.splice(index, 1);
|
||||
_this.setBlacklist();
|
||||
_this.blocklist.splice(index, 1);
|
||||
_this.setBlocklist();
|
||||
}
|
||||
}
|
||||
|
||||
if (action === "tablet") {
|
||||
var tabletIDs = message.blacklist ?
|
||||
var tabletIDs = message.blocklist ?
|
||||
[HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] :
|
||||
[];
|
||||
if (message.hand === LEFT_HAND) {
|
||||
_this.leftBlacklistTabletIDs = tabletIDs;
|
||||
_this.setLeftBlacklist();
|
||||
_this.leftBlocklistTabletIDs = tabletIDs;
|
||||
_this.setLeftBlocklist();
|
||||
} else {
|
||||
_this.rightBlacklistTabletIDs = tabletIDs;
|
||||
_this.setRightBlacklist();
|
||||
_this.rightBlocklistTabletIDs = tabletIDs;
|
||||
_this.setRightBlocklist();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Entities.mousePressOnEntity.connect(mousePress);
|
||||
|
||||
var controllerDispatcher = new ControllerDispatcher();
|
||||
Messages.subscribe('Hifi-Hand-RayPick-Blacklist');
|
||||
Messages.subscribe('Hifi-Hand-RayPick-Blocklist');
|
||||
Messages.messageReceived.connect(controllerDispatcher.handleMessage);
|
||||
|
||||
Picks.handLaserDelayChanged.connect(controllerDispatcher.handLaserDelayChanged);
|
||||
|
|
|
@ -299,7 +299,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
action: 'remove',
|
||||
id: this.ignoredEntities[i]
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data));
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));
|
||||
}
|
||||
this.ignoredEntities = [];
|
||||
};
|
||||
|
@ -394,7 +394,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
action: 'add',
|
||||
id: intersection.objectID
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data));
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));
|
||||
this.ignoredEntities.push(intersection.objectID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ Script.include("/~/system/libraries/utils.js");
|
|||
enableDispatcherModule("RightHandInEditMode", rightHandInEditMode);
|
||||
|
||||
var INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status";
|
||||
var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist";
|
||||
var HAND_RAYPICK_BLOCKLIST_CHANNEL = "Hifi-Hand-RayPick-Blocklist";
|
||||
this.handleMessage = function (channel, data, sender) {
|
||||
if (channel === INEDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) {
|
||||
var message;
|
||||
|
@ -247,10 +247,10 @@ Script.include("/~/system/libraries/utils.js");
|
|||
} else {
|
||||
rightHandInEditMode.isEditing = message.editing;
|
||||
}
|
||||
Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({
|
||||
Messages.sendLocalMessage(HAND_RAYPICK_BLOCKLIST_CHANNEL, JSON.stringify({
|
||||
action: "tablet",
|
||||
hand: message.hand,
|
||||
blacklist: message.editing
|
||||
blocklist: message.editing
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
enableDispatcherModule("RightHandInVREditMode", rightHandInVREditMode);
|
||||
|
||||
var INVREDIT_STATUS_CHANNEL = "Hifi-InVREdit-Status";
|
||||
var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist";
|
||||
var HAND_RAYPICK_BLOCKLIST_CHANNEL = "Hifi-Hand-RayPick-Blocklist";
|
||||
this.handleMessage = function (channel, data, sender) {
|
||||
if (channel === INVREDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) {
|
||||
var message;
|
||||
|
@ -168,10 +168,10 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
} else {
|
||||
rightHandInVREditMode.isEditing = message.editing;
|
||||
}
|
||||
Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({
|
||||
Messages.sendLocalMessage(HAND_RAYPICK_BLOCKLIST_CHANNEL, JSON.stringify({
|
||||
action: "tablet",
|
||||
hand: message.hand,
|
||||
blacklist: message.editing
|
||||
blocklist: message.editing
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
action: 'add',
|
||||
id: objectID
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data));
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));
|
||||
this.ignoredObjects.push(objectID);
|
||||
}
|
||||
} else if (intersection.type === Picks.INTERSECTED_ENTITY) {
|
||||
|
@ -122,7 +122,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
action: 'add',
|
||||
id: objectID
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data));
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));
|
||||
this.ignoredObjects.push(objectID);
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
action: 'remove',
|
||||
id: this.ignoredObjects[index]
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data));
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));
|
||||
}
|
||||
|
||||
this.ignoredObjects = [];
|
||||
|
|
|
@ -58,7 +58,7 @@ function runDefaultsTogether() {
|
|||
function runDefaultsSeparately() {
|
||||
for (var i in CONTOLLER_SCRIPTS) {
|
||||
if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) {
|
||||
print("loading " + CONTOLLER_SCRIPTS[j]);
|
||||
print("loading " + CONTOLLER_SCRIPTS[i]);
|
||||
Script.load(CONTOLLER_SCRIPTS[i]);
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue