diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp
index 779307c19d..cc6c4930ff 100644
--- a/assignment-client/src/audio/AudioMixer.cpp
+++ b/assignment-client/src/audio/AudioMixer.cpp
@@ -369,14 +369,6 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
reverbTime = _zoneReverbSettings[i].reverbTime;
wetLevel = _zoneReverbSettings[i].wetLevel;
- // Modulate wet level with distance to wall
- float MIN_ATTENUATION_DISTANCE = 2.0f;
- float MAX_ATTENUATION = -12; // dB
- glm::vec3 distanceToWalls = (box.getDimensions() / 2.0f) - glm::abs(streamPosition - box.calcCenter());
- float distanceToClosestWall = glm::min(distanceToWalls.x, distanceToWalls.z);
- if (distanceToClosestWall < MIN_ATTENUATION_DISTANCE) {
- wetLevel += MAX_ATTENUATION * (1.0f - distanceToClosestWall / MIN_ATTENUATION_DISTANCE);
- }
break;
}
}
diff --git a/cmake/externals/openvr/CMakeLists.txt b/cmake/externals/openvr/CMakeLists.txt
index 3fe7df44d0..930a339d12 100644
--- a/cmake/externals/openvr/CMakeLists.txt
+++ b/cmake/externals/openvr/CMakeLists.txt
@@ -7,8 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add(
${EXTERNAL_NAME}
- URL https://github.com/ValveSoftware/openvr/archive/v0.9.15.zip
- URL_MD5 0ff8560b49b6da1150fcc47360e8ceca
+ URL https://github.com/ValveSoftware/openvr/archive/v0.9.19.zip
+ URL_MD5 843f9dde488584d8af1f3ecf2252b4e0
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index 80ee32efa1..44a1796a8d 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -308,7 +308,7 @@
"name": "reverb",
"type": "table",
"label": "Reverb Settings",
- "help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet level of -10 db. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet level of -5 db.",
+ "help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet/dry mix of 25%. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet/dry mix of 50%.",
"numbered": true,
"columns": [
{
@@ -325,9 +325,9 @@
},
{
"name": "wet_level",
- "label": "Wet Level",
+ "label": "Wet/Dry Mix",
"can_set": true,
- "placeholder": "(in db)"
+ "placeholder": "(in percent)"
}
]
}
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index e3eb19dc4a..225a1d7957 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -451,6 +451,37 @@
var elPreviewCameraButton = document.getElementById("preview-camera-button");
+ var urlUpdaters = document.getElementsByClassName("update-url-version");
+ var PARAM_REGEXP = /(?:\?)(\S+)/; // Check if this has any parameters.
+ var TIMESTAMP_REGEXP = /(&?HFTime=\d+)/;
+
+ var refreshEvent = function(event){
+ var urlElement = event.target.parentElement.getElementsByClassName("url")[0];
+ var content = urlElement.value;
+ var date = new Date();
+ var timeStamp = date.getTime();
+
+ if(content.length > 0){
+ if(PARAM_REGEXP.test(content)){
+ // Has params, so lets remove existing definition and append again.
+ content = content.replace(TIMESTAMP_REGEXP,"") + "&";
+ }else{
+ content += "?";
+ }
+ content = content.replace("?&","?");
+ urlElement.value = content + "HFTime=" + timeStamp;
+ }
+
+ var evt = document.createEvent("HTMLEvents");
+ evt.initEvent("change", true, true );
+ urlElement.dispatchEvent(evt);
+ };
+
+ for(var index = 0; index < urlUpdaters.length; index++){
+ var urlUpdater = urlUpdaters[index];
+ urlUpdater.addEventListener("click", refreshEvent);
+ }
+
if (window.EventBridge !== undefined) {
var properties;
EventBridge.scriptEventReceived.connect(function(data) {
@@ -1185,6 +1216,7 @@
Ambient URL
@@ -1262,6 +1294,7 @@
Skybox URL
@@ -1273,6 +1306,7 @@
Source URL
@@ -1286,12 +1320,14 @@
Href - Hifi://address
@@ -1375,16 +1411,19 @@
X-axis Texture URL
Y-axis Texture URL
Z-axis Texture URL
@@ -1566,6 +1605,7 @@
Collision Sound URL
@@ -1583,6 +1623,7 @@
@@ -1595,6 +1636,7 @@
Model URL
@@ -1613,12 +1655,14 @@
Compound Shape URL
diff --git a/examples/html/style.css b/examples/html/style.css
index 83982dab15..3ae1c1739b 100644
--- a/examples/html/style.css
+++ b/examples/html/style.css
@@ -134,8 +134,18 @@ textarea {
resize: vertical;
}
+.update-url-version{
+ width:17px;
+ height:17px;
+ float:right;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAQAAACRZI9xAAABAUlEQVQoz33RvyvEARjH8SdlUX6UbhFJfgwmE3aTxWEiitxqN/gH7IxCKTcymLiJFIOJsihiUKcrCYnuXoZv+F45n2d4lvfz6fPpCSFs6BO1JllvLmXk5F37dC0vJ5NGmlBxoFp7Rn6RDpRRtG5KtynrijhLoBBGQcllKkFWAXsyCbKEFxeGqmJmFZFLkE639vX+12hCSVft0nUR8RbLcRN/aSHGIqL2tVYPconL32qLtaiL88Rl0qtXc+pTDv1OPGMlidtgS8Wp2RR05FEFM98/GlRQ9mTHvB7jVt2rKGPAT9xh2z6qfnToHV1SjZpN23Tl051di1oco9W/pdttaBRfEhFXOZV7vEsAAAAASUVORK5CYII=);
+ padding:0 !important;
+ margin:0 2px 0 0 !important;
+}
+
input.url {
- width: 100%;
+ width:85%;
+ padding-right: 20px;
}
input.coord {
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 89bddf7a90..c3e2b8284b 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1467,7 +1467,7 @@ void Application::paintGL() {
_lastFramesPerSecondUpdate = now;
}
- PROFILE_RANGE(__FUNCTION__);
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
PerformanceTimer perfTimer("paintGL");
if (nullptr == _displayPlugin) {
@@ -2608,11 +2608,12 @@ void Application::idle(uint64_t now) {
return;
}
+ PROFILE_RANGE(__FUNCTION__);
+
// We're going to execute idle processing, so restart the last idle timer
_lastTimeUpdated.start();
{
- PROFILE_RANGE(__FUNCTION__);
static uint64_t lastIdleStart{ now };
uint64_t idleStartToStartDuration = now - lastIdleStart;
if (idleStartToStartDuration != 0) {
@@ -3200,6 +3201,9 @@ void Application::updateDialogs(float deltaTime) {
}
void Application::update(float deltaTime) {
+
+ PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1);
+
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
@@ -3300,9 +3304,13 @@ void Application::update(float deltaTime) {
QSharedPointer
avatarManager = DependencyManager::get();
if (_physicsEnabled) {
+ PROFILE_RANGE_EX("Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
+
PerformanceTimer perfTimer("physics");
{
+ PROFILE_RANGE_EX("UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
+
PerformanceTimer perfTimer("updateStates)");
static VectorOfMotionStates motionStates;
_entitySimulation.getObjectsToRemoveFromPhysics(motionStates);
@@ -3335,12 +3343,14 @@ void Application::update(float deltaTime) {
});
}
{
+ PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PerformanceTimer perfTimer("stepSimulation");
getEntities()->getTree()->withWriteLock([&] {
_physicsEngine->stepSimulation();
});
}
{
+ PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
PerformanceTimer perfTimer("havestChanges");
if (_physicsEngine->hasOutgoingChanges()) {
getEntities()->getTree()->withWriteLock([&] {
@@ -3375,17 +3385,24 @@ void Application::update(float deltaTime) {
qApp->setAvatarSimrateSample(1.0f / deltaTime);
- avatarManager->updateOtherAvatars(deltaTime);
+ {
+ PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
+ avatarManager->updateOtherAvatars(deltaTime);
+ }
qApp->updateMyAvatarLookAtPosition();
// update sensorToWorldMatrix for camera and hand controllers
myAvatar->updateSensorToWorldMatrix();
- avatarManager->updateMyAvatar(deltaTime);
+ {
+ PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
+ avatarManager->updateMyAvatar(deltaTime);
+ }
}
{
+ PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PerformanceTimer perfTimer("overlays");
_overlays.update(deltaTime);
}
@@ -3405,6 +3422,7 @@ void Application::update(float deltaTime) {
// Update my voxel servers with my current voxel query...
{
+ PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PerformanceTimer perfTimer("queryOctree");
quint64 sinceLastQuery = now - _lastQueriedTime;
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
@@ -4731,13 +4749,18 @@ qreal Application::getDevicePixelRatio() {
}
DisplayPlugin* Application::getActiveDisplayPlugin() {
- std::unique_lock lock(_displayPluginLock);
- if (nullptr == _displayPlugin && QThread::currentThread() == thread()) {
- updateDisplayMode();
- Q_ASSERT(_displayPlugin);
+ DisplayPlugin* result = nullptr;
+ if (QThread::currentThread() == thread()) {
+ if (nullptr == _displayPlugin) {
+ updateDisplayMode();
+ Q_ASSERT(_displayPlugin);
+ }
+ result = _displayPlugin.get();
+ } else {
+ std::unique_lock lock(_displayPluginLock);
+ result = _displayPlugin.get();
}
-
- return _displayPlugin.get();
+ return result;
}
const DisplayPlugin* Application::getActiveDisplayPlugin() const {
@@ -4855,20 +4878,26 @@ void Application::updateDisplayMode() {
return;
}
- if (_displayPlugin) {
- _displayPlugin->deactivate();
- }
-
auto offscreenUi = DependencyManager::get();
- // FIXME probably excessive and useless context switching
- _offscreenContext->makeCurrent();
- newDisplayPlugin->activate();
- _offscreenContext->makeCurrent();
- offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize()));
- _offscreenContext->makeCurrent();
- getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
- _displayPlugin = newDisplayPlugin;
+ // Make the switch atomic from the perspective of other threads
+ {
+ std::unique_lock lock(_displayPluginLock);
+
+ if (_displayPlugin) {
+ _displayPlugin->deactivate();
+ }
+
+ // FIXME probably excessive and useless context switching
+ _offscreenContext->makeCurrent();
+ newDisplayPlugin->activate();
+ _offscreenContext->makeCurrent();
+ offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize()));
+ _offscreenContext->makeCurrent();
+ getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
+ _displayPlugin = newDisplayPlugin;
+ }
+
emit activeDisplayPluginChanged();
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 695d30998a..d21e647bc7 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -383,7 +383,7 @@ private:
OffscreenGLCanvas* _offscreenContext { nullptr };
DisplayPluginPointer _displayPlugin;
- std::recursive_mutex _displayPluginLock;
+ std::mutex _displayPluginLock;
InputPluginList _activeInputPlugins;
bool _activatingDisplayPlugin { false };
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index 7b63b7fc5a..f722210a8e 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -187,7 +187,7 @@ void Avatar::simulate(float deltaTime) {
// simple frustum check
float boundingRadius = getBoundingRadius();
- bool inView = qApp->getViewFrustum()->sphereIntersectsFrustum(getPosition(), boundingRadius);
+ bool inView = qApp->getDisplayViewFrustum()->sphereIntersectsFrustum(getPosition(), boundingRadius);
if (_shouldAnimate && !_shouldSkipRender && inView) {
{
diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp
index 620c35c832..5587096ce3 100644
--- a/interface/src/avatar/Head.cpp
+++ b/interface/src/avatar/Head.cpp
@@ -231,6 +231,13 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
_leftEyePosition = _rightEyePosition = getPosition();
_eyePosition = calculateAverageEyePosition();
+
+ if (!billboard && _owningAvatar) {
+ auto skeletonModel = static_cast(_owningAvatar)->getSkeletonModel();
+ if (skeletonModel) {
+ skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition);
+ }
+ }
}
void Head::calculateMouthShapes() {
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 8f11c635e9..210e6feb5b 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -897,7 +897,9 @@ void MyAvatar::updateLookAtTargetAvatar() {
// Scale by proportional differences between avatar and human.
float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye) * ipdScale;
float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye);
- gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation;
+ if (avatarEyeSeparation > 0.0f) {
+ gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation;
+ }
}
// And now we can finally add that offset to the camera.
diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp
index e222de54f9..70cf7e248f 100644
--- a/libraries/animation/src/AnimNodeLoader.cpp
+++ b/libraries/animation/src/AnimNodeLoader.cpp
@@ -611,7 +611,7 @@ AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& j
return loadNode(rootVal.toObject(), jsonUrl);
}
-void AnimNodeLoader::onRequestDone(const QByteArray& data) {
+void AnimNodeLoader::onRequestDone(const QByteArray data) {
auto node = load(data, _url);
if (node) {
emit success(node);
diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h
index 27b94f81bb..d6fdfa7e2c 100644
--- a/libraries/animation/src/AnimNodeLoader.h
+++ b/libraries/animation/src/AnimNodeLoader.h
@@ -36,7 +36,7 @@ protected:
static AnimNode::Pointer load(const QByteArray& contents, const QUrl& jsonUrl);
protected slots:
- void onRequestDone(const QByteArray& data);
+ void onRequestDone(const QByteArray data);
void onRequestError(QNetworkReply::NetworkError error);
protected:
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index ae9adc71c2..a2b664d064 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "AnimationLogging.h"
#include "AnimClip.h"
@@ -852,6 +853,8 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
+ PROFILE_RANGE_EX(__FUNCTION__, 0xffff00ff, 0);
+
setModelOffset(rootTransform);
if (_animNode) {
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 4d44a771f7..7e01196dc7 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -565,10 +565,10 @@ void AudioClient::updateReverbOptions() {
_zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime());
reverbChanged = true;
}
- //if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) {
- // _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel());
- // reverbChanged = true;
- //}
+ if (_zoneReverbOptions.getWetDryMix() != _receivedAudioStream.getWetLevel()) {
+ _zoneReverbOptions.setWetDryMix(_receivedAudioStream.getWetLevel());
+ reverbChanged = true;
+ }
if (_reverbOptions != &_zoneReverbOptions) {
_reverbOptions = &_zoneReverbOptions;
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index ca36ab35f0..d842dc553b 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -21,7 +21,7 @@
#include
#include
#include
-
+#include
#include
#include
#include
@@ -404,7 +404,11 @@ void OpenGLDisplayPlugin::submitOverlayTexture(const gpu::TexturePointer& overla
void OpenGLDisplayPlugin::updateTextures() {
// FIXME intrduce a GPU wait instead of a CPU/GPU sync point?
+#if THREADED_PRESENT
if (_sceneTextureEscrow.fetchSignaledAndRelease(_currentSceneTexture)) {
+#else
+ if (_sceneTextureEscrow.fetchAndReleaseWithGpuWait(_currentSceneTexture)) {
+#endif
updateFrameData();
}
@@ -527,6 +531,9 @@ void OpenGLDisplayPlugin::internalPresent() {
void OpenGLDisplayPlugin::present() {
incrementPresentCount();
+
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
+
updateTextures();
if (_currentSceneTexture) {
// Write all layers to a local framebuffer
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
index 501232f7e7..7295b07ad3 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
@@ -17,9 +17,9 @@
#include
#include
#include
-#include
#define THREADED_PRESENT 1
+#include
class OpenGLDisplayPlugin : public DisplayPlugin {
protected:
diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
index c3782b907f..b022b10887 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include "../Logging.h"
#include "../CompositorHelper.h"
@@ -106,6 +107,9 @@ void HmdDisplayPlugin::compositePointer() {
}
void HmdDisplayPlugin::internalPresent() {
+
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
+
// Composite together the scene, overlay and mouse cursor
hmdPresent();
@@ -149,6 +153,8 @@ void HmdDisplayPlugin::internalPresent() {
});
swapBuffers();
}
+
+ postPreview();
}
void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h
index 659a3a16fa..fede16c3a5 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h
@@ -31,6 +31,7 @@ public:
protected:
virtual void hmdPresent() = 0;
virtual bool isHmdMounted() const = 0;
+ virtual void postPreview() {};
void internalActivate() override;
void compositeOverlay() override;
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index ff4ed28150..98559a56a4 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -113,14 +113,18 @@ QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) {
return _originalTexturesMap;
}
- QString jsonTextures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}";
+ // Legacy: a ,\n-delimited list of filename:"texturepath"
+ if (*textures.cbegin() != '{') {
+ textures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}";
+ }
+
QJsonParseError error;
- QJsonDocument texturesAsJson = QJsonDocument::fromJson(jsonTextures.toUtf8(), &error);
+ QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures;
+ return _originalTexturesMap;
}
- QJsonObject texturesAsJsonObject = texturesAsJson.object();
- return texturesAsJsonObject.toVariantMap();
+ return texturesJson.object().toVariantMap();
}
void RenderableModelEntityItem::remapTextures() {
diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp
index 014ab33094..14bfc5ac7a 100644
--- a/libraries/entities/src/EntitySimulation.cpp
+++ b/libraries/entities/src/EntitySimulation.cpp
@@ -101,12 +101,15 @@ void EntitySimulation::expireMortalEntities(const quint64& now) {
prepareEntityForDelete(entity);
} else {
if (expiry < _nextExpiry) {
- // remeber the smallest _nextExpiry so we know when to start the next search
+ // remember the smallest _nextExpiry so we know when to start the next search
_nextExpiry = expiry;
}
++itemItr;
}
}
+ if (_mortalEntities.size() < 1) {
+ _nextExpiry = -1;
+ }
}
}
diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp
index b0b769d5e9..e5094a5224 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.cpp
+++ b/libraries/model-networking/src/model-networking/ModelCache.cpp
@@ -293,7 +293,7 @@ void NetworkGeometry::requestModel(const QUrl& url) {
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
}
-void NetworkGeometry::mappingRequestDone(const QByteArray& data) {
+void NetworkGeometry::mappingRequestDone(const QByteArray data) {
assert(_state == RequestMappingState);
// parse the mapping file
@@ -325,7 +325,7 @@ void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
emit onFailure(*this, MappingRequestError);
}
-void NetworkGeometry::modelRequestDone(const QByteArray& data) {
+void NetworkGeometry::modelRequestDone(const QByteArray data) {
assert(_state == RequestModelState);
_state = ParsingModelState;
diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index 1c76a0b878..550b16d2ba 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -113,10 +113,10 @@ public slots:
void textureLoaded(const QWeakPointer& networkTexture);
protected slots:
- void mappingRequestDone(const QByteArray& data);
+ void mappingRequestDone(const QByteArray data);
void mappingRequestError(QNetworkReply::NetworkError error);
- void modelRequestDone(const QByteArray& data);
+ void modelRequestDone(const QByteArray data);
void modelRequestError(QNetworkReply::NetworkError error);
void modelParseSuccess(FBXGeometry* geometry);
diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 58a82d5f11..28f4882b86 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -320,13 +320,12 @@ void ImageReader::run() {
}
QMetaObject::invokeMethod(texture.data(), "setImage",
- Q_ARG(const QImage&, image),
Q_ARG(void*, theTexture),
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
QThread::currentThread()->setPriority(originalPriority);
}
-void NetworkTexture::setImage(const QImage& image, void* voidTexture, int originalWidth,
+void NetworkTexture::setImage(void* voidTexture, int originalWidth,
int originalHeight) {
_originalWidth = originalWidth;
_originalHeight = originalHeight;
diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h
index 6fb0cc3177..858a40de36 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.h
+++ b/libraries/model-networking/src/model-networking/TextureCache.h
@@ -136,7 +136,7 @@ protected:
Q_INVOKABLE void loadContent(const QByteArray& content);
// FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on...
- Q_INVOKABLE void setImage(const QImage& image, void* texture, int originalWidth, int originalHeight);
+ Q_INVOKABLE void setImage(void* texture, int originalWidth, int originalHeight);
private:
diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp
index 3de94ed839..9738233c85 100644
--- a/libraries/networking/src/ResourceCache.cpp
+++ b/libraries/networking/src/ResourceCache.cpp
@@ -423,12 +423,12 @@ void Resource::handleReplyFinished() {
auto result = _request->getResult();
if (result == ResourceRequest::Success) {
- _data = _request->getData();
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
- emit loaded(_data);
- downloadFinished(_data);
+ auto data = _request->getData();
+ emit loaded(data);
+ downloadFinished(data);
} else {
switch (result) {
case ResourceRequest::Result::Timeout: {
diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h
index 77878794b5..7f4d86393b 100644
--- a/libraries/networking/src/ResourceCache.h
+++ b/libraries/networking/src/ResourceCache.h
@@ -194,12 +194,11 @@ public:
Q_INVOKABLE void allReferencesCleared();
const QUrl& getURL() const { return _url; }
- const QByteArray& getData() const { return _data; }
signals:
/// Fired when the resource has been downloaded.
/// This can be used instead of downloadFinished to access data before it is processed.
- void loaded(const QByteArray& request);
+ void loaded(const QByteArray request);
/// Fired when the resource has finished loading.
void finished(bool success);
@@ -235,7 +234,6 @@ protected:
QHash, float> _loadPriorities;
QWeakPointer _self;
QPointer _cache;
- QByteArray _data;
private slots:
void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal);
diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp
index 1d1a6628fe..d30be2c139 100644
--- a/libraries/networking/src/udt/CongestionControl.cpp
+++ b/libraries/networking/src/udt/CongestionControl.cpp
@@ -201,7 +201,7 @@ void DefaultCC::onTimeout() {
void DefaultCC::stopSlowStart() {
_slowStart = false;
-
+
if (_receiveRate > 0) {
// Set the sending rate to the receiving rate.
setPacketSendPeriod(USECS_PER_SECOND / _receiveRate);
diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp
index e5f3508b81..af70295840 100644
--- a/libraries/networking/src/udt/Connection.cpp
+++ b/libraries/networking/src/udt/Connection.cpp
@@ -103,6 +103,7 @@ SendQueue& Connection::getSendQueue() {
QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission);
QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive);
QObject::connect(_sendQueue.get(), &SendQueue::timeout, this, &Connection::queueTimeout);
+ QObject::connect(_sendQueue.get(), &SendQueue::shortCircuitLoss, this, &Connection::queueShortCircuitLoss);
// set defaults on the send queue from our congestion control object and estimatedTimeout()
_sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod);
@@ -140,6 +141,12 @@ void Connection::queueTimeout() {
});
}
+void Connection::queueShortCircuitLoss(quint32 sequenceNumber) {
+ updateCongestionControlAndSendQueue([this, sequenceNumber]{
+ _congestionControl->onLoss(SequenceNumber { sequenceNumber }, SequenceNumber { sequenceNumber });
+ });
+}
+
void Connection::sendReliablePacket(std::unique_ptr packet) {
Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably.");
getSendQueue().queuePacket(std::move(packet));
diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h
index 4f5a8793e7..08a2df9b97 100644
--- a/libraries/networking/src/udt/Connection.h
+++ b/libraries/networking/src/udt/Connection.h
@@ -87,6 +87,7 @@ private slots:
void recordRetransmission();
void queueInactive();
void queueTimeout();
+ void queueShortCircuitLoss(quint32 sequenceNumber);
private:
void sendACK(bool wasCausedBySyncTimeout = true);
diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp
index 9701561ec7..2ffa42cb82 100644
--- a/libraries/networking/src/udt/SendQueue.cpp
+++ b/libraries/networking/src/udt/SendQueue.cpp
@@ -128,13 +128,13 @@ void SendQueue::stop() {
_emptyCondition.notify_one();
}
-void SendQueue::sendPacket(const Packet& packet) {
- _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination);
+int SendQueue::sendPacket(const Packet& packet) {
+ return _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination);
}
void SendQueue::ack(SequenceNumber ack) {
// this is a response from the client, re-set our timeout expiry and our last response time
- _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch());
+ _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
if (_lastACKSequenceNumber == (uint32_t) ack) {
return;
@@ -164,7 +164,7 @@ void SendQueue::ack(SequenceNumber ack) {
void SendQueue::nak(SequenceNumber start, SequenceNumber end) {
// this is a response from the client, re-set our timeout expiry
- _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch());
+ _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
{
std::lock_guard nakLocker(_naksLock);
@@ -177,8 +177,8 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) {
void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) {
// this is a response from the client, re-set our timeout expiry
- _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch());
-
+ _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
+
{
std::lock_guard nakLocker(_naksLock);
_naks.clear();
@@ -232,15 +232,16 @@ SequenceNumber SendQueue::getNextSequenceNumber() {
return _currentSequenceNumber;
}
-void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) {
+bool SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) {
// write the sequence number and send the packet
newPacket->writeSequenceNumber(sequenceNumber);
- sendPacket(*newPacket);
-
+
// Save packet/payload size before we move it
auto packetSize = newPacket->getDataSize();
auto payloadSize = newPacket->getPayloadSize();
+ auto bytesWritten = sendPacket(*newPacket);
+
{
// Insert the packet we have just sent in the sent list
QWriteLocker locker(&_sentLock);
@@ -249,8 +250,24 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket,
entry.second.swap(newPacket);
}
Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list");
-
+
emit packetSent(packetSize, payloadSize);
+
+ if (bytesWritten < 0) {
+ // this is a short-circuit loss - we failed to put this packet on the wire
+ // so immediately add it to the loss list
+
+ {
+ std::lock_guard nakLocker(_naksLock);
+ _naks.append(sequenceNumber);
+ }
+
+ emit shortCircuitLoss(quint32(sequenceNumber));
+
+ return false;
+ } else {
+ return true;
+ }
}
void SendQueue::run() {
@@ -285,12 +302,14 @@ void SendQueue::run() {
auto nextPacketTimestamp = p_high_resolution_clock::now();
while (_state == State::Running) {
- bool sentAPacket = maybeResendPacket();
+ bool attemptedToSendPacket = maybeResendPacket();
// if we didn't find a packet to re-send AND we think we can fit a new packet on the wire
// (this is according to the current flow window size) then we send out a new packet
- if (!sentAPacket) {
- sentAPacket = maybeSendNewPacket();
+ auto newPacketCount = 0;
+ if (!attemptedToSendPacket) {
+ newPacketCount = maybeSendNewPacket();
+ attemptedToSendPacket = (newPacketCount > 0);
}
// since we're a while loop, give the thread a chance to process events
@@ -300,12 +319,13 @@ void SendQueue::run() {
// If the send queue has been innactive, skip the sleep for
// Either _isRunning will have been set to false and we'll break
// Or something happened and we'll keep going
- if (_state != State::Running || isInactive(sentAPacket)) {
+ if (_state != State::Running || isInactive(attemptedToSendPacket)) {
return;
}
// push the next packet timestamp forwards by the current packet send period
- nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod);
+ auto nextPacketDelta = (newPacketCount == 2 ? 2 : 1) * _packetSendPeriod;
+ nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta);
// sleep as long as we need until next packet send, if we can
const auto timeToSleep = duration_cast(nextPacketTimestamp - p_high_resolution_clock::now());
@@ -314,7 +334,7 @@ void SendQueue::run() {
}
}
-bool SendQueue::maybeSendNewPacket() {
+int SendQueue::maybeSendNewPacket() {
if (!isFlowWindowFull()) {
// we didn't re-send a packet, so time to send a new one
@@ -324,38 +344,43 @@ bool SendQueue::maybeSendNewPacket() {
// grab the first packet we will send
std::unique_ptr firstPacket = _packets.takePacket();
Q_ASSERT(firstPacket);
-
- std::unique_ptr secondPacket;
- bool shouldSendPairTail = false;
-
- if (((uint32_t) nextNumber & 0xF) == 0) {
- // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets
- // pull off a second packet if we can before we unlock
- shouldSendPairTail = true;
-
- secondPacket = _packets.takePacket();
+
+
+ // attempt to send the first packet
+ if (sendNewPacketAndAddToSentList(move(firstPacket), nextNumber)) {
+ std::unique_ptr secondPacket;
+ bool shouldSendPairTail = false;
+
+ if (((uint32_t) nextNumber & 0xF) == 0) {
+ // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets
+ // pull off a second packet if we can before we unlock
+ shouldSendPairTail = true;
+
+ secondPacket = _packets.takePacket();
+ }
+
+ // do we have a second in a pair to send as well?
+ if (secondPacket) {
+ sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber());
+ } else if (shouldSendPairTail) {
+ // we didn't get a second packet to send in the probe pair
+ // send a control packet of type ProbePairTail so the receiver can still do
+ // proper bandwidth estimation
+ static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail);
+ _socket->writeBasePacket(*pairTailPacket, _destination);
+ }
+
+ // we attempted to send two packets, return 2
+ return 2;
+ } else {
+ // we attempted to send a single packet, return 1
+ return 1;
}
-
- // definitely send the first packet
- sendNewPacketAndAddToSentList(move(firstPacket), nextNumber);
-
- // do we have a second in a pair to send as well?
- if (secondPacket) {
- sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber());
- } else if (shouldSendPairTail) {
- // we didn't get a second packet to send in the probe pair
- // send a control packet of type ProbePairTail so the receiver can still do
- // proper bandwidth estimation
- static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail);
- _socket->writeBasePacket(*pairTailPacket, _destination);
- }
-
- // We sent our packet(s), return here
- return true;
}
}
+
// No packets were sent
- return false;
+ return 0;
}
bool SendQueue::maybeResendPacket() {
@@ -375,8 +400,9 @@ bool SendQueue::maybeResendPacket() {
// see if we can find the packet to re-send
auto it = _sentPackets.find(resendNumber);
-
+
if (it != _sentPackets.end()) {
+
auto& entry = it->second;
// we found the packet - grab it
auto& resendPacket = *(entry.second);
@@ -437,7 +463,7 @@ bool SendQueue::maybeResendPacket() {
return false;
}
-bool SendQueue::isInactive(bool sentAPacket) {
+bool SendQueue::isInactive(bool attemptedToSendPacket) {
// check for connection timeout first
// that will be the case if we have had 16 timeouts since hearing back from the client, and it has been
@@ -447,7 +473,8 @@ bool SendQueue::isInactive(bool sentAPacket) {
auto sinceLastResponse = (QDateTime::currentMSecsSinceEpoch() - _lastReceiverResponse);
- if (sinceLastResponse >= quint64(NUM_TIMEOUTS_BEFORE_INACTIVE * (_estimatedTimeout / USECS_PER_MSEC)) &&
+ if (sinceLastResponse > 0 &&
+ sinceLastResponse >= int64_t(NUM_TIMEOUTS_BEFORE_INACTIVE * (_estimatedTimeout / USECS_PER_MSEC)) &&
_lastReceiverResponse > 0 &&
sinceLastResponse > MIN_MS_BEFORE_INACTIVE) {
// If the flow window has been full for over CONSIDER_INACTIVE_AFTER,
@@ -462,7 +489,7 @@ bool SendQueue::isInactive(bool sentAPacket) {
return true;
}
- if (!sentAPacket) {
+ if (!attemptedToSendPacket) {
// During our processing above we didn't send any packets
// If that is still the case we should use a condition_variable_any to sleep until we have data to handle.
diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h
index 9400ae8352..21f6141c3c 100644
--- a/libraries/networking/src/udt/SendQueue.h
+++ b/libraries/networking/src/udt/SendQueue.h
@@ -79,6 +79,7 @@ signals:
void queueInactive();
+ void shortCircuitLoss(quint32 sequenceNumber);
void timeout();
private slots:
@@ -91,13 +92,13 @@ private:
void sendHandshake();
- void sendPacket(const Packet& packet);
- void sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber);
+ int sendPacket(const Packet& packet);
+ bool sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber);
- bool maybeSendNewPacket(); // Figures out what packet to send next
+ int maybeSendNewPacket(); // Figures out what packet to send next
bool maybeResendPacket(); // Determines whether to resend a packet and which one
- bool isInactive(bool sentAPacket);
+ bool isInactive(bool attemptedToSendPacket);
void deactivate(); // makes the queue inactive and cleans it up
bool isFlowWindowFull() const;
@@ -122,7 +123,7 @@ private:
std::atomic _estimatedTimeout { 0 }; // Estimated timeout, set from CC
std::atomic _syncInterval { udt::DEFAULT_SYN_INTERVAL_USECS }; // Sync interval, set from CC
- std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK)
+ std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK)
std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC
diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp
index 497ed2031f..2d219915c8 100644
--- a/libraries/physics/src/PhysicalEntitySimulation.cpp
+++ b/libraries/physics/src/PhysicalEntitySimulation.cpp
@@ -57,16 +57,18 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
}
void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
- EntitySimulation::removeEntityInternal(entity);
- QMutexLocker lock(&_mutex);
- _entitiesToAddToPhysics.remove(entity);
+ if (entity->isSimulated()) {
+ EntitySimulation::removeEntityInternal(entity);
+ QMutexLocker lock(&_mutex);
+ _entitiesToAddToPhysics.remove(entity);
- EntityMotionState* motionState = static_cast(entity->getPhysicsInfo());
- if (motionState) {
- _outgoingChanges.remove(motionState);
- _entitiesToRemoveFromPhysics.insert(entity);
- } else {
- _entitiesToDelete.insert(entity);
+ EntityMotionState* motionState = static_cast(entity->getPhysicsInfo());
+ if (motionState) {
+ _outgoingChanges.remove(motionState);
+ _entitiesToRemoveFromPhysics.insert(entity);
+ } else {
+ _entitiesToDelete.insert(entity);
+ }
}
}
@@ -175,7 +177,7 @@ void PhysicalEntitySimulation::getObjectsToRemoveFromPhysics(VectorOfMotionState
_entitiesToRelease.insert(entity);
}
- if (entity->isSimulated() && entity->isDead()) {
+ if (entity->isDead()) {
_entitiesToDelete.insert(entity);
}
}
@@ -190,7 +192,7 @@ void PhysicalEntitySimulation::deleteObjectsRemovedFromPhysics() {
entity->setPhysicsInfo(nullptr);
delete motionState;
- if (entity->isSimulated() && entity->isDead()) {
+ if (entity->isDead()) {
_entitiesToDelete.insert(entity);
}
}
diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp
index 484f049944..56805e8f83 100644
--- a/libraries/render/src/render/CullTask.cpp
+++ b/libraries/render/src/render/CullTask.cpp
@@ -114,6 +114,7 @@ void FetchSpatialTree::run(const SceneContextPointer& sceneContext, const Render
void CullSpatialSelection::configure(const Config& config) {
_justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum);
_freezeFrustum = config.freezeFrustum;
+ _skipCulling = config.skipCulling;
}
void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext,
@@ -191,60 +192,112 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
// visibility cull if partially selected ( octree cell contianing it was partial)
// distance cull if was a subcell item ( octree cell is way bigger than the item bound itself, so now need to test per item)
- // inside & fit items: easy, just filter
- {
- PerformanceTimer perfTimer("insideFitItems");
- for (auto id : inSelection.insideItems) {
- auto& item = scene->getItem(id);
- if (_filter.test(item.getKey())) {
- ItemBound itemBound(id, item.getBound());
- outItems.emplace_back(itemBound);
- }
- }
- }
-
- // inside & subcell items: filter & distance cull
- {
- PerformanceTimer perfTimer("insideSmallItems");
- for (auto id : inSelection.insideSubcellItems) {
- auto& item = scene->getItem(id);
- if (_filter.test(item.getKey())) {
- ItemBound itemBound(id, item.getBound());
- if (test.solidAngleTest(itemBound.bound)) {
+ if (_skipCulling) {
+ // inside & fit items: filter only, culling is disabled
+ {
+ PerformanceTimer perfTimer("insideFitItems");
+ for (auto id : inSelection.insideItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
}
}
}
- }
- // partial & fit items: filter & frustum cull
- {
- PerformanceTimer perfTimer("partialFitItems");
- for (auto id : inSelection.partialItems) {
- auto& item = scene->getItem(id);
- if (_filter.test(item.getKey())) {
- ItemBound itemBound(id, item.getBound());
- if (test.frustumTest(itemBound.bound)) {
+ // inside & subcell items: filter only, culling is disabled
+ {
+ PerformanceTimer perfTimer("insideSmallItems");
+ for (auto id : inSelection.insideSubcellItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
}
}
}
- }
- // partial & subcell items:: filter & frutum cull & solidangle cull
- {
- PerformanceTimer perfTimer("partialSmallItems");
- for (auto id : inSelection.partialSubcellItems) {
- auto& item = scene->getItem(id);
- if (_filter.test(item.getKey())) {
- ItemBound itemBound(id, item.getBound());
- if (test.frustumTest(itemBound.bound)) {
+ // partial & fit items: filter only, culling is disabled
+ {
+ PerformanceTimer perfTimer("partialFitItems");
+ for (auto id : inSelection.partialItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
+ outItems.emplace_back(itemBound);
+ }
+ }
+ }
+
+ // partial & subcell items: filter only, culling is disabled
+ {
+ PerformanceTimer perfTimer("partialSmallItems");
+ for (auto id : inSelection.partialSubcellItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
+ outItems.emplace_back(itemBound);
+ }
+ }
+ }
+
+ } else {
+
+ // inside & fit items: easy, just filter
+ {
+ PerformanceTimer perfTimer("insideFitItems");
+ for (auto id : inSelection.insideItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
+ outItems.emplace_back(itemBound);
+ }
+ }
+ }
+
+ // inside & subcell items: filter & distance cull
+ {
+ PerformanceTimer perfTimer("insideSmallItems");
+ for (auto id : inSelection.insideSubcellItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
if (test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound);
}
}
}
}
+
+ // partial & fit items: filter & frustum cull
+ {
+ PerformanceTimer perfTimer("partialFitItems");
+ for (auto id : inSelection.partialItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
+ if (test.frustumTest(itemBound.bound)) {
+ outItems.emplace_back(itemBound);
+ }
+ }
+ }
+ }
+
+ // partial & subcell items:: filter & frutum cull & solidangle cull
+ {
+ PerformanceTimer perfTimer("partialSmallItems");
+ for (auto id : inSelection.partialSubcellItems) {
+ auto& item = scene->getItem(id);
+ if (_filter.test(item.getKey())) {
+ ItemBound itemBound(id, item.getBound());
+ if (test.frustumTest(itemBound.bound)) {
+ if (test.solidAngleTest(itemBound.bound)) {
+ outItems.emplace_back(itemBound);
+ }
+ }
+ }
+ }
+ }
}
details._rendered += (int)outItems.size();
diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h
index a6a32e4561..e84f018e91 100644
--- a/libraries/render/src/render/CullTask.h
+++ b/libraries/render/src/render/CullTask.h
@@ -70,14 +70,16 @@ namespace render {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
Q_PROPERTY(bool freezeFrustum MEMBER freezeFrustum WRITE setFreezeFrustum)
+ Q_PROPERTY(bool skipCulling MEMBER skipCulling WRITE setSkipCulling)
public:
int numItems{ 0 };
int getNumItems() { return numItems; }
bool freezeFrustum{ false };
+ bool skipCulling{ false };
public slots:
void setFreezeFrustum(bool enabled) { freezeFrustum = enabled; emit dirty(); }
-
+ void setSkipCulling(bool enabled) { skipCulling = enabled; emit dirty(); }
signals:
void dirty();
};
@@ -85,6 +87,7 @@ namespace render {
class CullSpatialSelection {
bool _freezeFrustum{ false }; // initialized by Config
bool _justFrozeFrustum{ false };
+ bool _skipCulling{ false };
ViewFrustum _frozenFrutstum;
public:
using Config = CullSpatialSelectionConfig;
diff --git a/libraries/shared/src/shared/NsightHelpers.cpp b/libraries/shared/src/shared/NsightHelpers.cpp
index e48e228588..2539ff8864 100644
--- a/libraries/shared/src/shared/NsightHelpers.cpp
+++ b/libraries/shared/src/shared/NsightHelpers.cpp
@@ -8,6 +8,7 @@
#include "NsightHelpers.h"
+#ifdef _WIN32
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
@@ -15,8 +16,28 @@ ProfileRange::ProfileRange(const char *name) {
nvtxRangePush(name);
}
+ProfileRange::ProfileRange(const char *name, uint32_t argbColor, uint64_t payload) {
+
+ nvtxEventAttributes_t eventAttrib = {0};
+ eventAttrib.version = NVTX_VERSION;
+ eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE;
+ eventAttrib.colorType = NVTX_COLOR_ARGB;
+ eventAttrib.color = argbColor;
+ eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII;
+ eventAttrib.message.ascii = name;
+ eventAttrib.payload.llValue = payload;
+ eventAttrib.payloadType = NVTX_PAYLOAD_TYPE_UNSIGNED_INT64;
+
+ nvtxRangePushEx(&eventAttrib);
+}
+
ProfileRange::~ProfileRange() {
nvtxRangePop();
}
+#else
+ProfileRange::ProfileRange(const char *name) {}
+ProfileRange::ProfileRange(const char *name, uint32_t argbColor, uint64_t payload) {}
+ProfileRange::~ProfileRange() {}
#endif
+#endif // _WIN32
diff --git a/libraries/shared/src/shared/NsightHelpers.h b/libraries/shared/src/shared/NsightHelpers.h
index 3acdf14411..9853171b34 100644
--- a/libraries/shared/src/shared/NsightHelpers.h
+++ b/libraries/shared/src/shared/NsightHelpers.h
@@ -9,16 +9,21 @@
#ifndef hifi_gl_NsightHelpers_h
#define hifi_gl_NsightHelpers_h
-#if defined(NSIGHT_FOUND)
- class ProfileRange {
- public:
- ProfileRange(const char *name);
- ~ProfileRange();
- };
+#ifdef _WIN32
+#include
+
+class ProfileRange {
+public:
+ ProfileRange(const char *name);
+ ProfileRange(const char *name, uint32_t argbColor, uint64_t payload);
+ ~ProfileRange();
+};
+
#define PROFILE_RANGE(name) ProfileRange profileRangeThis(name);
+#define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, payload);
#else
#define PROFILE_RANGE(name)
+#define PROFILE_RANGE_EX(name, argbColor, payload)
#endif
-
-#endif
\ No newline at end of file
+#endif
diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp
index f12fb51b19..0228f77f4f 100644
--- a/libraries/ui/src/QmlWebWindowClass.cpp
+++ b/libraries/ui/src/QmlWebWindowClass.cpp
@@ -31,19 +31,18 @@ static const char* const URL_PROPERTY = "source";
// Method called by Qt scripts to create a new web window in the overlay
QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
return QmlWindowClass::internalConstructor("QmlWebWindow.qml", context, engine,
- [&](QObject* object) { return new QmlWebWindowClass(object); });
+ [&](QObject* object) { return new QmlWebWindowClass(object); });
}
QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) : QmlWindowClass(qmlWindow) {
}
-// FIXME remove.
-void QmlWebWindowClass::handleNavigation(const QString& url) {
-}
-
QString QmlWebWindowClass::getURL() const {
QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant {
+ if (_qmlWindow.isNull()) {
+ return QVariant();
+ }
return _qmlWindow->property(URL_PROPERTY);
});
return result.toString();
@@ -54,6 +53,8 @@ extern QString fixupHifiUrl(const QString& urlString);
void QmlWebWindowClass::setURL(const QString& urlString) {
DependencyManager::get()->executeOnUiThread([=] {
- _qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString));
+ if (!_qmlWindow.isNull()) {
+ _qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString));
+ }
});
}
diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h
index 14e533c7b4..27c0e6996d 100644
--- a/libraries/ui/src/QmlWebWindowClass.h
+++ b/libraries/ui/src/QmlWebWindowClass.h
@@ -26,9 +26,6 @@ public slots:
signals:
void urlChanged();
-
-private slots:
- void handleNavigation(const QString& url);
};
#endif
diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp
index 679e86f4ae..b7fe330a4e 100644
--- a/libraries/ui/src/QmlWindowClass.cpp
+++ b/libraries/ui/src/QmlWindowClass.cpp
@@ -214,7 +214,7 @@ QmlWindowClass::QmlWindowClass(QObject* qmlWindow)
{
qDebug() << "Created window with ID " << _windowId;
Q_ASSERT(_qmlWindow);
- Q_ASSERT(dynamic_cast(_qmlWindow));
+ Q_ASSERT(dynamic_cast(_qmlWindow.data()));
// Forward messages received from QML on to the script
connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(const QVariant&)), Qt::QueuedConnection);
}
@@ -240,7 +240,7 @@ QQuickItem* QmlWindowClass::asQuickItem() const {
if (_toolWindow) {
return DependencyManager::get()->getToolWindow();
}
- return dynamic_cast(_qmlWindow);
+ return _qmlWindow.isNull() ? nullptr : dynamic_cast(_qmlWindow.data());
}
void QmlWindowClass::setVisible(bool visible) {
@@ -260,32 +260,34 @@ void QmlWindowClass::setVisible(bool visible) {
bool QmlWindowClass::isVisible() const {
// The tool window itself has special logic based on whether any tabs are enabled
- if (_toolWindow) {
- auto targetTab = dynamic_cast(_qmlWindow);
- return DependencyManager::get()->returnFromUiThread([&] {
- return QVariant::fromValue(targetTab->isEnabled());
- }).toBool();
- } else {
- QQuickItem* targetWindow = asQuickItem();
- return DependencyManager::get()->returnFromUiThread([&] {
- return QVariant::fromValue(targetWindow->isVisible());
- }).toBool();
- }
+ return DependencyManager::get()->returnFromUiThread([&] {
+ if (_qmlWindow.isNull()) {
+ return QVariant::fromValue(false);
+ }
+ if (_toolWindow) {
+ return QVariant::fromValue(dynamic_cast(_qmlWindow.data())->isEnabled());
+ } else {
+ return QVariant::fromValue(asQuickItem()->isVisible());
+ }
+ }).toBool();
}
glm::vec2 QmlWindowClass::getPosition() const {
- QQuickItem* targetWindow = asQuickItem();
QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant {
- return targetWindow->position();
+ if (_qmlWindow.isNull()) {
+ return QVariant(QPointF(0, 0));
+ }
+ return asQuickItem()->position();
});
return toGlm(result.toPointF());
}
void QmlWindowClass::setPosition(const glm::vec2& position) {
- QQuickItem* targetWindow = asQuickItem();
DependencyManager::get()->executeOnUiThread([=] {
- targetWindow->setPosition(QPointF(position.x, position.y));
+ if (!_qmlWindow.isNull()) {
+ asQuickItem()->setPosition(QPointF(position.x, position.y));
+ }
});
}
@@ -299,17 +301,21 @@ glm::vec2 toGlm(const QSizeF& size) {
}
glm::vec2 QmlWindowClass::getSize() const {
- QQuickItem* targetWindow = asQuickItem();
QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant {
+ if (_qmlWindow.isNull()) {
+ return QVariant(QSizeF(0, 0));
+ }
+ QQuickItem* targetWindow = asQuickItem();
return QSizeF(targetWindow->width(), targetWindow->height());
});
return toGlm(result.toSizeF());
}
void QmlWindowClass::setSize(const glm::vec2& size) {
- QQuickItem* targetWindow = asQuickItem();
DependencyManager::get()->executeOnUiThread([=] {
- targetWindow->setSize(QSizeF(size.x, size.y));
+ if (!_qmlWindow.isNull()) {
+ asQuickItem()->setSize(QSizeF(size.x, size.y));
+ }
});
}
@@ -318,9 +324,10 @@ void QmlWindowClass::setSize(int width, int height) {
}
void QmlWindowClass::setTitle(const QString& title) {
- QQuickItem* targetWindow = asQuickItem();
DependencyManager::get()->executeOnUiThread([=] {
- targetWindow->setProperty(TITLE_PROPERTY, title);
+ if (!_qmlWindow.isNull()) {
+ asQuickItem()->setProperty(TITLE_PROPERTY, title);
+ }
});
}
@@ -345,7 +352,12 @@ void QmlWindowClass::hasClosed() {
}
void QmlWindowClass::raise() {
- QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::QueuedConnection);
+ auto offscreenUi = DependencyManager::get();
+ offscreenUi->executeOnUiThread([=] {
+ if (!_qmlWindow.isNull()) {
+ QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::DirectConnection);
+ }
+ });
}
#include "QmlWindowClass.moc"
diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h
index 26152b1f24..fb7dbf1253 100644
--- a/libraries/ui/src/QmlWindowClass.h
+++ b/libraries/ui/src/QmlWindowClass.h
@@ -10,11 +10,13 @@
#define hifi_ui_QmlWindowClass_h
#include
-#include
+#include
#include
#include
#include
+#include
+
class QScriptEngine;
class QScriptContext;
class QmlWindowClass;
@@ -38,14 +40,13 @@ private:
const QmlWindowClass* _webWindow { nullptr };
QWebSocket *_socket { nullptr };
};
-
// FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping
class QmlWindowClass : public QObject {
Q_OBJECT
Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT)
Q_PROPERTY(int windowId READ getWindowId CONSTANT)
- Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition)
- Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize)
+ Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition NOTIFY positionChanged)
+ Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged)
public:
@@ -64,11 +65,8 @@ public slots:
glm::vec2 getSize() const;
void setSize(const glm::vec2& size);
void setSize(int width, int height);
-
void setTitle(const QString& title);
-
- // Ugh.... do not want to do
Q_INVOKABLE void raise();
Q_INVOKABLE void close();
Q_INVOKABLE int getWindowId() const { return _windowId; };
@@ -79,6 +77,8 @@ public slots:
signals:
void visibilityChanged(bool visible); // Tool window
+ void positionChanged();
+ void sizeChanged();
void moved(glm::vec2 position);
void resized(QSizeF size);
void closed();
@@ -104,7 +104,7 @@ protected:
// for tool window panes in QML
bool _toolWindow { false };
const int _windowId;
- QObject* _qmlWindow;
+ QPointer _qmlWindow;
QString _source;
};
diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp
index 5ab56e1659..71a858e1e8 100644
--- a/plugins/oculus/src/OculusDisplayPlugin.cpp
+++ b/plugins/oculus/src/OculusDisplayPlugin.cpp
@@ -6,6 +6,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusDisplayPlugin.h"
+#include
#include "OculusHelpers.h"
const QString OculusDisplayPlugin::NAME("Oculus Rift");
@@ -54,6 +55,9 @@ void OculusDisplayPlugin::updateFrameData() {
}
void OculusDisplayPlugin::hmdPresent() {
+
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex)
+
if (!_currentSceneTexture) {
return;
}
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 0cd9bac15f..0e7541066e 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -21,7 +21,7 @@
#include
#include
#include
-
+#include
#include "OpenVrHelpers.h"
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
@@ -69,6 +69,9 @@ void OpenVrDisplayPlugin::internalActivate() {
_compositor = vr::VRCompositor();
Q_ASSERT(_compositor);
+ // enable async time warp
+ // _compositor->ForceInterleavedReprojectionOn(true);
+
// set up default sensor space such that the UI overlay will align with the front of the room.
auto chaperone = vr::VRChaperone();
if (chaperone) {
@@ -119,14 +122,11 @@ void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
float vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
#if THREADED_PRESENT
- // TODO: this seems awfuly long, 44ms total, but it produced the best results.
+ // 3 frames of prediction + vsyncToPhotons = 44ms total
const float NUM_PREDICTION_FRAMES = 3.0f;
float predictedSecondsFromNow = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons;
#else
- uint64_t frameCounter;
- float timeSinceLastVsync;
- _system->GetTimeSinceLastVsync(&timeSinceLastVsync, &frameCounter);
- float predictedSecondsFromNow = 3.0f * frameDuration - timeSinceLastVsync + vsyncToPhotons;
+ float predictedSecondsFromNow = frameDuration + vsyncToPhotons;
#endif
vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
@@ -144,6 +144,9 @@ void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
}
void OpenVrDisplayPlugin::hmdPresent() {
+
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex)
+
// Flip y-axis since GL UV coords are backwards.
static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 };
@@ -152,6 +155,10 @@ void OpenVrDisplayPlugin::hmdPresent() {
_compositor->Submit(vr::Eye_Left, &texture, &leftBounds);
_compositor->Submit(vr::Eye_Right, &texture, &rightBounds);
+}
+
+void OpenVrDisplayPlugin::postPreview() {
+ PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex)
vr::TrackedDevicePose_t currentTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
_compositor->WaitGetPoses(currentTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h
index caaf75a4d0..78b76cb78d 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.h
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.h
@@ -35,6 +35,7 @@ protected:
void hmdPresent() override;
bool isHmdMounted() const override;
+ void postPreview() override;
private:
vr::IVRSystem* _system { nullptr };
diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp
index d2c3649933..8ddf028dd2 100644
--- a/plugins/openvr/src/OpenVrHelpers.cpp
+++ b/plugins/openvr/src/OpenVrHelpers.cpp
@@ -51,7 +51,7 @@ vr::IVRSystem* acquireOpenVrSystem() {
if (!activeHmd) {
qCDebug(displayplugins) << "openvr: No vr::IVRSystem instance active, building";
vr::EVRInitError eError = vr::VRInitError_None;
- activeHmd = vr::VR_Init(&eError);
+ activeHmd = vr::VR_Init(&eError, vr::VRApplication_Scene);
qCDebug(displayplugins) << "openvr display: HMD is " << activeHmd << " error is " << eError;
}
if (activeHmd) {
diff --git a/server-console/src/log.js b/server-console/src/log.js
index e45848e5a5..3634eaeaa7 100644
--- a/server-console/src/log.js
+++ b/server-console/src/log.js
@@ -44,6 +44,14 @@ ready = function() {
var domainServer = remote.getGlobal('domainServer');
var acMonitor = remote.getGlobal('acMonitor');
+ var pendingLines = {
+ 'ds': new Array(),
+ 'ac': new Array()
+ };
+
+ var UPDATE_INTERVAL = 16; // Update log at ~60 fps
+ var interval = setInterval(flushPendingLines, UPDATE_INTERVAL);
+
var logWatchers = {
'ds': {
},
@@ -83,7 +91,7 @@ ready = function() {
var logTail = new Tail(cleanFilePath, '\n', { start: start, interval: 500 });
logTail.on('line', function(msg) {
- appendLogMessage(msg, stream);
+ pendingLines[stream].push(msg);
});
logTail.on('error', function(error) {
@@ -107,6 +115,7 @@ ready = function() {
}
window.onbeforeunload = function(e) {
+ clearInterval(interval);
domainServer.removeListener('logs-updated', updateLogFiles);
acMonitor.removeListener('logs-updated', updateLogFiles);
};
@@ -164,14 +173,23 @@ ready = function() {
return !filter || message.toLowerCase().indexOf(filter) >= 0;
}
- function appendLogMessage(msg, name) {
+ function appendLogMessages(name) {
+ var array = pendingLines[name];
+ if (array.length === 0) {
+ return;
+ }
+ if (array.length > maxLogLines) {
+ array = array.slice(-maxLogLines);
+ }
+
+ console.log(name, array.length);
+
var id = name == "ds" ? "domain-server" : "assignment-client";
var $pidLog = $('#' + id);
- var size = ++tabStates[id].size;
+ var size = tabStates[id].size + array.length;
if (size > maxLogLines) {
- $pidLog.find('div.log-line:first').remove();
- removed = true;
+ $pidLog.find('div.log-line:lt(' + (size - maxLogLines) + ')').remove();
}
var wasAtBottom = false;
@@ -179,17 +197,25 @@ ready = function() {
wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height());
}
- var $logLine = $('').text(msg);
- if (!shouldDisplayLogMessage(msg)) {
- $logLine.hide();
+ for (line in array) {
+ var $logLine = $('
').text(array[line]);
+ if (!shouldDisplayLogMessage(array[line])) {
+ $logLine.hide();
+ }
+
+ $pidLog.append($logLine);
}
- $pidLog.append($logLine);
+ delete pendingLines[name];
+ pendingLines[name] = new Array();
if (wasAtBottom) {
$pidLog.scrollTop($pidLog[0].scrollHeight);
}
-
+ }
+ function flushPendingLines() {
+ appendLogMessages('ds');
+ appendLogMessages('ac');
}
// handle filtering of table rows on input change
diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp
index 533e6371e9..2b5e306b09 100644
--- a/tools/udt-test/src/UDTTest.cpp
+++ b/tools/udt-test/src/UDTTest.cpp
@@ -77,7 +77,7 @@ UDTTest::UDTTest(int& argc, char** argv) :
// randomize the seed for packet size randomization
srand(time(NULL));
-
+
_socket.bind(QHostAddress::AnyIPv4, _argumentParser.value(PORT_OPTION).toUInt());
qDebug() << "Test socket is listening on" << _socket.localPort();