diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp
index 43bc922c74..06fb5c4f47 100644
--- a/assignment-client/src/octree/OctreeServer.cpp
+++ b/assignment-client/src/octree/OctreeServer.cpp
@@ -327,6 +327,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
showStats = true;
} else if (url.path() == "/resetStats") {
_octreeInboundPacketProcessor->resetStats();
+ _tree->resetEditStats();
resetSendingStats();
showStats = true;
}
@@ -627,6 +628,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
// display inbound packet stats
statsString += QString().sprintf("%s Edit Statistics... [RESET]\r\n",
getMyServerName());
+ quint64 currentPacketsInQueue = _octreeInboundPacketProcessor->packetsToProcessCount();
quint64 averageTransitTimePerPacket = _octreeInboundPacketProcessor->getAverageTransitTimePerPacket();
quint64 averageProcessTimePerPacket = _octreeInboundPacketProcessor->getAverageProcessTimePerPacket();
quint64 averageLockWaitTimePerPacket = _octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();
@@ -635,8 +637,18 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
quint64 totalElementsProcessed = _octreeInboundPacketProcessor->getTotalElementsProcessed();
quint64 totalPacketsProcessed = _octreeInboundPacketProcessor->getTotalPacketsProcessed();
+ quint64 averageDecodeTime = _tree->getAverageDecodeTime();
+ quint64 averageLookupTime = _tree->getAverageLookupTime();
+ quint64 averageUpdateTime = _tree->getAverageUpdateTime();
+ quint64 averageCreateTime = _tree->getAverageCreateTime();
+ quint64 averageLoggingTime = _tree->getAverageLoggingTime();
+
+
float averageElementsPerPacket = totalPacketsProcessed == 0 ? 0 : totalElementsProcessed / totalPacketsProcessed;
+ statsString += QString(" Current Inbound Packets Queue: %1 packets\r\n")
+ .arg(locale.toString((uint)currentPacketsInQueue).rightJustified(COLUMN_WIDTH, ' '));
+
statsString += QString(" Total Inbound Packets: %1 packets\r\n")
.arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));
statsString += QString(" Total Inbound Elements: %1 elements\r\n")
@@ -654,6 +666,17 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
statsString += QString(" Average Wait Lock Time/Element: %1 usecs\r\n")
.arg(locale.toString((uint)averageLockWaitTimePerElement).rightJustified(COLUMN_WIDTH, ' '));
+ statsString += QString(" Average Decode Time: %1 usecs\r\n")
+ .arg(locale.toString((uint)averageDecodeTime).rightJustified(COLUMN_WIDTH, ' '));
+ statsString += QString(" Average Lookup Time: %1 usecs\r\n")
+ .arg(locale.toString((uint)averageLookupTime).rightJustified(COLUMN_WIDTH, ' '));
+ statsString += QString(" Average Update Time: %1 usecs\r\n")
+ .arg(locale.toString((uint)averageUpdateTime).rightJustified(COLUMN_WIDTH, ' '));
+ statsString += QString(" Average Create Time: %1 usecs\r\n")
+ .arg(locale.toString((uint)averageCreateTime).rightJustified(COLUMN_WIDTH, ' '));
+ statsString += QString(" Average Logging Time: %1 usecs\r\n")
+ .arg(locale.toString((uint)averageLoggingTime).rightJustified(COLUMN_WIDTH, ' '));
+
int senderNumber = 0;
NodeToSenderStatsMap& allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats();
@@ -1411,6 +1434,8 @@ void OctreeServer::sendStatsPacket() {
static QJsonObject statsObject3;
+ statsObject3[baseName + QString(".3.inbound.data.1.packetQueue")] =
+ (double)_octreeInboundPacketProcessor->packetsToProcessCount();
statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] =
(double)_octreeInboundPacketProcessor->getTotalPacketsProcessed();
statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] =
diff --git a/examples/animationPerfTest.js b/examples/animationPerfTest.js
new file mode 100644
index 0000000000..6bf310db23
--- /dev/null
+++ b/examples/animationPerfTest.js
@@ -0,0 +1,91 @@
+//
+// Created by Bradley Austin Davis on 2015/07/01
+// Copyright 2015 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+var NUM_MOONS = 20;
+// 1 = 60Hz, 2 = 30Hz, 3 = 20Hz, etc
+var UPDATE_FREQUENCY_DIVISOR = 2;
+
+var MAX_RANGE = 75.0;
+var LIFETIME = 600;
+var SCALE = 0.1;
+
+var center = Vec3.sum(MyAvatar.position,
+ Vec3.multiply(MAX_RANGE * SCALE, Quat.getFront(Camera.getOrientation())));
+
+var DEGREES_TO_RADIANS = Math.PI / 180.0;
+var PARTICLE_MIN_SIZE = 2.50;
+var PARTICLE_MAX_SIZE = 2.50;
+
+
+var planet = Entities.addEntity({
+ type: "Sphere",
+ position: center,
+ dimensions: { x: 10 * SCALE, y: 10 * SCALE, z: 10 * SCALE },
+ color: { red: 0, green: 0, blue: 255 },
+ ignoreCollisions: true,
+ collisionsWillMove: false,
+ lifetime: LIFETIME
+});
+
+var moons = [];
+
+// Create initial test particles that will move according to gravity from the planets
+for (var i = 0; i < NUM_MOONS; i++) {
+ var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE;
+ radius *= SCALE;
+ var gray = Math.random() * 155;
+ var position = { x: 10 , y: i * 3, z: 0 };
+ var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray };
+ if (i == 0) {
+ color = { red: 255, green: 0, blue: 0 };
+ radius = 6 * SCALE
+ }
+ moons.push(Entities.addEntity({
+ type: "Sphere",
+ position: Vec3.sum(center, position),
+ dimensions: { x: radius, y: radius, z: radius },
+ color: color,
+ ignoreCollisions: true,
+ lifetime: LIFETIME,
+ collisionsWillMove: false
+ }));
+}
+
+Script.update.connect(update);
+
+function scriptEnding() {
+ Entities.deleteEntity(planet);
+ for (var i = 0; i < moons.length; i++) {
+ Entities.deleteEntity(moons[i]);
+ }
+}
+
+var totalTime = 0.0;
+var updateCount = 0;
+function update(deltaTime) {
+ // Apply gravitational force from planets
+ totalTime += deltaTime;
+ updateCount++;
+ if (0 != updateCount % UPDATE_FREQUENCY_DIVISOR) {
+ return;
+ }
+
+ var planetProperties = Entities.getEntityProperties(planet);
+ var center = planetProperties.position;
+ var particlePos = Entities.getEntityProperties(moons[0]).position;
+ var relativePos = Vec3.subtract(particlePos.position, center);
+ for (var t = 0; t < moons.length; t++) {
+ var thetaDelta = (Math.PI * 2.0 / NUM_MOONS) * t;
+ var y = Math.sin(totalTime + thetaDelta) * 10.0 * SCALE;
+ var x = Math.cos(totalTime + thetaDelta) * 10.0 * SCALE;
+ var newBasePos = Vec3.sum({ x: 0, y: y, z: x }, center);
+ Entities.editEntity(moons[t], { position: newBasePos});
+ }
+}
+
+Script.scriptEnding.connect(scriptEnding);
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index d68a3813a9..ca264fd42f 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -91,6 +91,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -178,6 +179,7 @@ using namespace std;
// Starfield information
static unsigned STARFIELD_NUM_STARS = 50000;
static unsigned STARFIELD_SEED = 1;
+static uint8_t THROTTLED_IDLE_TIMER_DELAY = 10;
const qint64 MAXIMUM_CACHE_SIZE = 10 * BYTES_PER_GIGABYTES; // 10GB
@@ -1037,7 +1039,7 @@ void Application::showEditEntitiesHelp() {
InfoView::show(INFO_EDIT_ENTITIES_PATH);
}
-void Application::resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size) {
+void Application::resetCameras(Camera& camera, const glm::uvec2& size) {
if (OculusManager::isConnected()) {
OculusManager::configureCamera(camera);
} else if (TV3DManager::isConnected()) {
@@ -1060,7 +1062,6 @@ void Application::resizeGL() {
if (_renderResolution != toGlm(renderSize)) {
_renderResolution = toGlm(renderSize);
DependencyManager::get()->setFrameBufferSize(renderSize);
- resetCamerasOnResizeGL(_myCamera, _renderResolution);
glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu???
@@ -1068,6 +1069,8 @@ void Application::resizeGL() {
glLoadIdentity();
}
+ resetCameras(_myCamera, _renderResolution);
+
auto offscreenUi = DependencyManager::get();
auto canvasSize = _glWidget->size();
@@ -1784,8 +1787,22 @@ void Application::checkFPS() {
}
void Application::idle() {
- PerformanceTimer perfTimer("idle");
+ static SimpleAverage interIdleDurations;
+ static uint64_t lastIdleEnd{ 0 };
+ if (lastIdleEnd != 0) {
+ uint64_t now = usecTimestampNow();
+ interIdleDurations.update(now - lastIdleEnd);
+ static uint64_t lastReportTime = now;
+ if ((now - lastReportTime) >= (USECS_PER_SECOND)) {
+ static QString LOGLINE("Average inter-idle time: %1 us for %2 samples");
+ qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount());
+ interIdleDurations.reset();
+ lastReportTime = now;
+ }
+ }
+
+ PerformanceTimer perfTimer("idle");
if (_aboutToQuit) {
return; // bail early, nothing to do here.
}
@@ -1828,13 +1845,15 @@ void Application::idle() {
_idleLoopStdev.reset();
}
- // After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
- idleTimer->start(2);
}
- }
+ // After finishing all of the above work, ensure the idle timer is set to the proper interval,
+ // depending on whether we're throttling or not
+ idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 0);
+ }
// check for any requested background downloads.
emit checkBackgroundDownloads();
+ lastIdleEnd = usecTimestampNow();
}
void Application::setFullscreen(bool fullscreen) {
@@ -3542,7 +3561,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
//Render the sixense lasers
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
- _myAvatar->renderLaserPointers();
+ _myAvatar->renderLaserPointers(*renderArgs->_batch);
}
if (!selfAvatarOnly) {
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 375aded8ac..1d3c0dcc70 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -483,7 +483,7 @@ private slots:
void setCursorVisible(bool visible);
private:
- void resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size);
+ void resetCameras(Camera& camera, const glm::uvec2& size);
void updateProjectionMatrix();
void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true);
diff --git a/interface/src/InterfaceLogging.cpp b/interface/src/InterfaceLogging.cpp
index 18bc4e58e8..0afcb30c27 100644
--- a/interface/src/InterfaceLogging.cpp
+++ b/interface/src/InterfaceLogging.cpp
@@ -12,3 +12,4 @@
#include "InterfaceLogging.h"
Q_LOGGING_CATEGORY(interfaceapp, "hifi.interface")
+Q_LOGGING_CATEGORY(interfaceapp_timing, "hifi.interface.timing")
diff --git a/interface/src/InterfaceLogging.h b/interface/src/InterfaceLogging.h
index d1d92aa93d..be2ee73fba 100644
--- a/interface/src/InterfaceLogging.h
+++ b/interface/src/InterfaceLogging.h
@@ -15,5 +15,6 @@
#include
Q_DECLARE_LOGGING_CATEGORY(interfaceapp)
+Q_DECLARE_LOGGING_CATEGORY(interfaceapp_timing)
#endif // hifi_InterfaceLogging_h
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index d0778481a6..63b08b693c 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -449,26 +449,26 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
}
if (renderBounding && shouldRenderHead(renderArgs)) {
- _skeletonModel.renderBoundingCollisionShapes(0.7f);
+ _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f);
}
+ }
- // If this is the avatar being looked at, render a little ball above their head
- if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
- const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
- const float LOOK_AT_INDICATOR_OFFSET = 0.22f;
- const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
- glm::vec3 position;
- if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
- position = glm::vec3(_position.x, getDisplayNamePosition().y, _position.z);
- } else {
- position = glm::vec3(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
- }
- Transform transform;
- transform.setTranslation(position);
- batch.setModelTransform(transform);
- DependencyManager::get()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS
- , 15, 15, LOOK_AT_INDICATOR_COLOR);
+ // If this is the avatar being looked at, render a little ball above their head
+ if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
+ const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
+ const float LOOK_AT_INDICATOR_OFFSET = 0.22f;
+ const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
+ glm::vec3 position;
+ if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
+ position = glm::vec3(_position.x, getDisplayNamePosition().y, _position.z);
+ } else {
+ position = glm::vec3(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
}
+ Transform transform;
+ transform.setTranslation(position);
+ batch.setModelTransform(transform);
+ DependencyManager::get()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS
+ , 15, 15, LOOK_AT_INDICATOR_COLOR);
}
// quick check before falling into the code below:
@@ -1010,7 +1010,7 @@ int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
int Avatar::_jointConesID = GeometryCache::UNKNOWN_ID;
// render a makeshift cone section that serves as a body part connecting joint spheres
-void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
+void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2,
float radius1, float radius2, const glm::vec4& color) {
auto geometryCache = DependencyManager::get();
@@ -1057,7 +1057,7 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
// TODO: this is really inefficient constantly recreating these vertices buffers. It would be
// better if the avatars cached these buffers for each of the joints they are rendering
geometryCache->updateVertices(_jointConesID, points, color);
- geometryCache->renderVertices(gpu::TRIANGLES, _jointConesID);
+ geometryCache->renderVertices(batch, gpu::TRIANGLES, _jointConesID);
}
}
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index 236b04864b..b23059acb0 100644
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -148,7 +148,7 @@ public:
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
- static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
+ static void renderJointConnectingCone( gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2,
float radius1, float radius2, const glm::vec4& color);
virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { }
diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp
index 74653d9768..7b2968973c 100644
--- a/interface/src/avatar/Hand.cpp
+++ b/interface/src/avatar/Hand.cpp
@@ -103,7 +103,8 @@ void Hand::resolvePenetrations() {
}
void Hand::render(RenderArgs* renderArgs, bool isMine) {
- if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE &&
+ gpu::Batch& batch = *renderArgs->_batch;
+ if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE &&
Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
// draw a green sphere at hand joint location, which is actually near the wrist)
for (size_t i = 0; i < getNumPalms(); i++) {
@@ -112,31 +113,25 @@ void Hand::render(RenderArgs* renderArgs, bool isMine) {
continue;
}
glm::vec3 position = palm.getPosition();
- glPushMatrix();
- glTranslatef(position.x, position.y, position.z);
- DependencyManager::get()->renderSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10, glm::vec3(0.0f, 1.0f, 0.0f));
- glPopMatrix();
+ Transform transform = Transform();
+ transform.setTranslation(position);
+ batch.setModelTransform(transform);
+ DependencyManager::get()->renderSphere(batch, PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10, glm::vec3(0.0f, 1.0f, 0.0f));
}
}
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
- renderHandTargets(isMine);
+ renderHandTargets(renderArgs, isMine);
}
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_RESCALE_NORMAL);
-}
-
-void Hand::renderHandTargets(bool isMine) {
- glPushMatrix();
+}
+void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
+ gpu::Batch& batch = *renderArgs->_batch;
const float avatarScale = DependencyManager::get()->getMyAvatar()->getScale();
const float alpha = 1.0f;
const glm::vec3 handColor(1.0, 0.0, 0.0); // Color the hand targets red to be different than skin
-
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_TRUE);
if (isMine && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) {
for (size_t i = 0; i < getNumPalms(); ++i) {
@@ -145,12 +140,12 @@ void Hand::renderHandTargets(bool isMine) {
continue;
}
glm::vec3 targetPosition = palm.getTipPosition();
- glPushMatrix();
- glTranslatef(targetPosition.x, targetPosition.y, targetPosition.z);
+ Transform transform = Transform();
+ transform.setTranslation(targetPosition);
+ batch.setModelTransform(transform);
const float collisionRadius = 0.05f;
- DependencyManager::get()->renderSphere(collisionRadius, 10, 10, glm::vec4(0.5f,0.5f,0.5f, alpha), false);
- glPopMatrix();
+ DependencyManager::get()->renderSphere(batch, collisionRadius, 10, 10, glm::vec4(0.5f,0.5f,0.5f, alpha), false);
}
}
@@ -165,22 +160,19 @@ void Hand::renderHandTargets(bool isMine) {
if (palm.isActive()) {
glm::vec3 tip = palm.getTipPosition();
glm::vec3 root = palm.getPosition();
-
- Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
+ Transform transform = Transform();
+ transform.setTranslation(glm::vec3());
+ batch.setModelTransform(transform);
+ Avatar::renderJointConnectingCone(batch, root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
// Render sphere at palm/finger root
glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS;
- Avatar::renderJointConnectingCone(root, offsetFromPalm, PALM_DISK_RADIUS, 0.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
- glPushMatrix();
- glTranslatef(root.x, root.y, root.z);
- DependencyManager::get()->renderSphere(PALM_BALL_RADIUS, 20.0f, 20.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
- glPopMatrix();
+ Avatar::renderJointConnectingCone(batch, root, offsetFromPalm, PALM_DISK_RADIUS, 0.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
+ transform = Transform();
+ transform.setTranslation(root);
+ batch.setModelTransform(transform);
+ DependencyManager::get()->renderSphere(batch, PALM_BALL_RADIUS, 20.0f, 20.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
}
}
-
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
-
- glPopMatrix();
}
diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h
index cb35497960..f6991c5a55 100644
--- a/interface/src/avatar/Hand.h
+++ b/interface/src/avatar/Hand.h
@@ -56,7 +56,7 @@ private:
Avatar* _owningAvatar;
- void renderHandTargets(bool isMine);
+ void renderHandTargets(RenderArgs* renderArgs, bool isMine);
};
#endif // hifi_Hand_h
diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp
index 27888b9d4e..911bd4f4a4 100644
--- a/interface/src/avatar/Head.cpp
+++ b/interface/src/avatar/Head.cpp
@@ -9,9 +9,11 @@
//
#include
+#include
+#include
#include
-#include
+#include
#include
#include "Application.h"
@@ -293,10 +295,8 @@ void Head::relaxLean(float deltaTime) {
}
void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting) {
- if (postLighting) {
- if (_renderLookatVectors) {
+ if (_renderLookatVectors) {
renderLookatVectors(renderArgs, _leftEyePosition, _rightEyePosition, getLookAtPosition());
- }
}
}
@@ -367,17 +367,19 @@ void Head::addLeanDeltas(float sideways, float forward) {
}
void Head::renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
+ auto& batch = *renderArgs->_batch;
+ auto transform = Transform{};
+ batch.setModelTransform(transform);
+ batch._glLineWidth(2.0f);
+
+ auto deferredLighting = DependencyManager::get();
+ deferredLighting->bindSimpleProgram(batch);
+
auto geometryCache = DependencyManager::get();
- DependencyManager::get()->begin(renderArgs);
-
- glLineWidth(2.0);
-
glm::vec4 startColor(0.2f, 0.2f, 0.2f, 1.0f);
glm::vec4 endColor(1.0f, 1.0f, 1.0f, 0.0f);
- geometryCache->renderLine(leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID);
- geometryCache->renderLine(rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID);
-
- DependencyManager::get()->end(renderArgs);
+ geometryCache->renderLine(batch, leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID);
+ geometryCache->renderLine(batch, rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID);
}
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 170fc03d17..03b8a56526 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1208,9 +1208,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo
if (shouldRenderHead(renderArgs)) {
getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
}
- if (postLighting) {
- getHand()->render(renderArgs, true);
- }
+ getHand()->render(renderArgs, true);
}
void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) {
@@ -1584,7 +1582,7 @@ void MyAvatar::updateMotionBehavior() {
}
//Renders sixense laser pointers for UI selection with controllers
-void MyAvatar::renderLaserPointers() {
+void MyAvatar::renderLaserPointers(gpu::Batch& batch) {
const float PALM_TIP_ROD_RADIUS = 0.002f;
//If the Oculus is enabled, we will draw a blue cursor ray
@@ -1597,8 +1595,10 @@ void MyAvatar::renderLaserPointers() {
//Scale the root vector with the avatar scale
scaleVectorRelativeToPosition(root);
-
- Avatar::renderJointConnectingCone(root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
+ Transform transform = Transform();
+ transform.setTranslation(glm::vec3());
+ batch.setModelTransform(transform);
+ Avatar::renderJointConnectingCone(batch, root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
}
}
}
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index daec7d3457..d09cff1394 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -163,7 +163,7 @@ public:
bool allowDuplicates = false, bool useSaved = true);
/// Renders a laser pointer for UI picking
- void renderLaserPointers();
+ void renderLaserPointers(gpu::Batch& batch);
glm::vec3 getLaserPointerTipPosition(const PalmData* palm);
const RecorderPointer getRecorder() const { return _recorder; }
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 2f66e84b50..20d458195d 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -776,24 +776,24 @@ void SkeletonModel::resetShapePositionsToDefaultPose() {
_boundingShape.setRotation(_rotation);
}
-void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
+void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) {
const int BALL_SUBDIVISIONS = 10;
if (_shapes.isEmpty()) {
// the bounding shape has not been propery computed
// so no need to render it
return;
}
- glPushMatrix();
-
Application::getInstance()->loadTranslatedViewMatrix(_translation);
// draw a blue sphere at the capsule endpoint
glm::vec3 endPoint;
_boundingShape.getEndPoint(endPoint);
endPoint = endPoint - _translation;
- glTranslatef(endPoint.x, endPoint.y, endPoint.z);
+ Transform transform = Transform();
+ transform.setTranslation(endPoint);
+ batch.setModelTransform(transform);
auto geometryCache = DependencyManager::get();
- geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
+ geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
// draw a yellow sphere at the capsule startpoint
glm::vec3 startPoint;
@@ -805,9 +805,7 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
// draw a green cylinder between the two points
glm::vec3 origin(0.0f);
- Avatar::renderJointConnectingCone( origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha));
-
- glPopMatrix();
+ Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha));
}
bool SkeletonModel::hasSkeleton() {
diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h
index bffdc58659..755aa3dfee 100644
--- a/interface/src/avatar/SkeletonModel.h
+++ b/interface/src/avatar/SkeletonModel.h
@@ -101,7 +101,7 @@ public:
const glm::vec3& getStandingOffset() const { return _standingOffset; }
void computeBoundingShape(const FBXGeometry& geometry);
- void renderBoundingCollisionShapes(float alpha);
+ void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha);
float getBoundingShapeRadius() const { return _boundingShape.getRadius(); }
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
const glm::vec3 getBoundingShapeOffset() const { return _boundingShapeLocalOffset; }
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index eca250a428..93b3ef8d07 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -221,8 +221,6 @@ void PreferencesDialog::savePreferences() {
myAvatar->setLeanScale(ui.leanScaleSpin->value());
myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value());
- Application::getInstance()->resizeGL();
-
DependencyManager::get()->getMyAvatar()->setRealWorldFieldOfView(ui.realWorldFieldOfViewSpin->value());
qApp->setFieldOfView(ui.fieldOfViewSpin->value());
diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp
index ccad3bd295..3f033d9266 100644
--- a/interface/src/ui/overlays/TextOverlay.cpp
+++ b/interface/src/ui/overlays/TextOverlay.cpp
@@ -170,3 +170,11 @@ QSizeF TextOverlay::textSize(const QString& text) const {
return QSizeF(extents.x, extents.y);
}
+
+void TextOverlay::setFontSize(int fontSize) {
+ _fontSize = fontSize;
+
+ auto oldTextRenderer = _textRenderer;
+ _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
+ delete oldTextRenderer;
+}
diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h
index de2597cf9a..32786c3220 100644
--- a/interface/src/ui/overlays/TextOverlay.h
+++ b/interface/src/ui/overlays/TextOverlay.h
@@ -48,7 +48,7 @@ public:
void setText(const QString& text) { _text = text; }
void setLeftMargin(int margin) { _leftMargin = margin; }
void setTopMargin(int margin) { _topMargin = margin; }
- void setFontSize(int fontSize) { _fontSize = fontSize; }
+ void setFontSize(int fontSize);
virtual void setProperties(const QScriptValue& properties);
virtual TextOverlay* createClone() const;
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 752082932b..6a652d609b 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -574,41 +574,61 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
case PacketTypeEntityAdd:
case PacketTypeEntityEdit: {
+ quint64 startDecode = 0, endDecode = 0;
+ quint64 startLookup = 0, endLookup = 0;
+ quint64 startUpdate = 0, endUpdate = 0;
+ quint64 startCreate = 0, endCreate = 0;
+ quint64 startLogging = 0, endLogging = 0;
+
+ _totalEditMessages++;
+
EntityItemID entityItemID;
EntityItemProperties properties;
+ startDecode = usecTimestampNow();
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength,
processedBytes, entityItemID, properties);
+ endDecode = usecTimestampNow();
// If we got a valid edit packet, then it could be a new entity or it could be an update to
// an existing entity... handle appropriately
if (validEditPacket) {
// search for the entity by EntityItemID
+ startLookup = usecTimestampNow();
EntityItemPointer existingEntity = findEntityByEntityItemID(entityItemID);
+ endLookup = usecTimestampNow();
if (existingEntity && packetType == PacketTypeEntityEdit) {
// if the EntityItem exists, then update it
+ startLogging = usecTimestampNow();
if (wantEditLogging()) {
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
}
+ endLogging = usecTimestampNow();
+
+ startUpdate = usecTimestampNow();
updateEntity(entityItemID, properties, senderNode);
existingEntity->markAsChangedOnServer();
+ endUpdate = usecTimestampNow();
+ _totalUpdates++;
} else if (packetType == PacketTypeEntityAdd) {
if (senderNode->getCanRez()) {
// this is a new entity... assign a new entityID
- if (wantEditLogging()) {
- qCDebug(entities) << "User [" << senderNode->getUUID() << "] adding entity.";
- qCDebug(entities) << " properties:" << properties;
- }
properties.setCreated(properties.getLastEdited());
+ startCreate = usecTimestampNow();
EntityItemPointer newEntity = addEntity(entityItemID, properties);
+ endCreate = usecTimestampNow();
+ _totalCreates++;
if (newEntity) {
newEntity->markAsChangedOnServer();
notifyNewlyCreatedEntity(*newEntity, senderNode);
+
+ startLogging = usecTimestampNow();
if (wantEditLogging()) {
qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:"
<< newEntity->getEntityItemID();
qCDebug(entities) << " properties:" << properties;
}
+ endLogging = usecTimestampNow();
}
} else {
@@ -619,6 +639,14 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity.get();
}
}
+
+
+ _totalDecodeTime += endDecode - startDecode;
+ _totalLookupTime += endLookup - startLookup;
+ _totalUpdateTime += endUpdate - startUpdate;
+ _totalCreateTime += endCreate - startCreate;
+ _totalLoggingTime += endLogging - startLogging;
+
break;
}
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 9c4be9a86f..fa72cc7691 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -168,6 +168,23 @@ public:
float getContentsLargestDimension();
+ virtual void resetEditStats() {
+ _totalEditMessages = 0;
+ _totalUpdates = 0;
+ _totalCreates = 0;
+ _totalDecodeTime = 0;
+ _totalLookupTime = 0;
+ _totalUpdateTime = 0;
+ _totalCreateTime = 0;
+ _totalLoggingTime = 0;
+ }
+
+ virtual quint64 getAverageDecodeTime() const { return _totalEditMessages == 0 ? 0 : _totalDecodeTime / _totalEditMessages; }
+ virtual quint64 getAverageLookupTime() const { return _totalEditMessages == 0 ? 0 : _totalLookupTime / _totalEditMessages; }
+ virtual quint64 getAverageUpdateTime() const { return _totalUpdates == 0 ? 0 : _totalUpdateTime / _totalUpdates; }
+ virtual quint64 getAverageCreateTime() const { return _totalCreates == 0 ? 0 : _totalCreateTime / _totalCreates; }
+ virtual quint64 getAverageLoggingTime() const { return _totalEditMessages == 0 ? 0 : _totalLoggingTime / _totalEditMessages; }
+
signals:
void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID);
@@ -202,6 +219,17 @@ private:
bool _wantEditLogging = false;
void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL);
+
+
+ // some performance tracking properties - only used in server trees
+ int _totalEditMessages = 0;
+ int _totalUpdates = 0;
+ int _totalCreates = 0;
+ quint64 _totalDecodeTime = 0;
+ quint64 _totalLookupTime = 0;
+ quint64 _totalUpdateTime = 0;
+ quint64 _totalCreateTime = 0;
+ quint64 _totalLoggingTime = 0;
};
#endif // hifi_EntityTree_h
diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp
index 894a7b8aa9..3c4b32b4ec 100644
--- a/libraries/networking/src/ReceivedPacketProcessor.cpp
+++ b/libraries/networking/src/ReceivedPacketProcessor.cpp
@@ -38,19 +38,28 @@ bool ReceivedPacketProcessor::process() {
_hasPackets.wait(&_waitingOnPacketsMutex, getMaxWait());
_waitingOnPacketsMutex.unlock();
}
+
preProcess();
- while (_packets.size() > 0) {
- lock(); // lock to make sure nothing changes on us
- NetworkPacket& packet = _packets.front(); // get the oldest packet
- NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us
- _packets.erase(_packets.begin()); // remove the oldest packet
- if (!temporary.getNode().isNull()) {
- _nodePacketCounts[temporary.getNode()->getUUID()]--;
- }
- unlock(); // let others add to the packets
- processPacket(temporary.getNode(), temporary.getByteArray()); // process our temporary copy
+ if (!_packets.size()) {
+ return isStillRunning();
+ }
+
+ lock();
+ QVector currentPackets;
+ currentPackets.swap(_packets);
+ unlock();
+
+ foreach(auto& packet, currentPackets) {
+ processPacket(packet.getNode(), packet.getByteArray());
midProcess();
}
+
+ lock();
+ foreach(auto& packet, currentPackets) {
+ _nodePacketCounts[packet.getNode()->getUUID()]--;
+ }
+ unlock();
+
postProcess();
return isStillRunning(); // keep running till they terminate us
}
diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h
index d7fc58699f..6eeb423ddd 100644
--- a/libraries/octree/src/Octree.h
+++ b/libraries/octree/src/Octree.h
@@ -367,8 +367,16 @@ public:
bool getIsClient() const { return !_isServer; } /// Is this a client based tree. Allows guards for certain operations
void setIsClient(bool isClient) { _isServer = !isClient; }
- virtual void dumpTree() { };
- virtual void pruneTree() { };
+ virtual void dumpTree() { }
+ virtual void pruneTree() { }
+
+ virtual void resetEditStats() { }
+ virtual quint64 getAverageDecodeTime() const { return 0; }
+ virtual quint64 getAverageLookupTime() const { return 0; }
+ virtual quint64 getAverageUpdateTime() const { return 0; }
+ virtual quint64 getAverageCreateTime() const { return 0; }
+ virtual quint64 getAverageLoggingTime() const { return 0; }
+
signals:
void importSize(float x, float y, float z);
diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp
index c14fd33565..b60ffc0891 100644
--- a/libraries/shared/src/SettingInterface.cpp
+++ b/libraries/shared/src/SettingInterface.cpp
@@ -11,6 +11,7 @@
#include
#include
+#include
#include
#include "PathUtils.h"
@@ -53,7 +54,15 @@ namespace Setting {
privateInstance = new Manager();
Q_CHECK_PTR(privateInstance);
-
+
+ // Delete Interface.ini.lock file if it exists, otherwise Interface freezes.
+ QString settingsLockFilename = privateInstance->fileName() + ".lock";
+ QFile settingsLockFile(settingsLockFilename);
+ if (settingsLockFile.exists()) {
+ bool deleted = settingsLockFile.remove();
+ qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename;
+ }
+
QObject::connect(privateInstance, SIGNAL(destroyed()), thread, SLOT(quit()));
QObject::connect(thread, SIGNAL(started()), privateInstance, SLOT(startTimer()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
diff --git a/libraries/shared/src/SimpleAverage.h b/libraries/shared/src/SimpleAverage.h
new file mode 100644
index 0000000000..33ed9d84cc
--- /dev/null
+++ b/libraries/shared/src/SimpleAverage.h
@@ -0,0 +1,33 @@
+//
+// Created by Bradley Austin Davis on 2015/07/01.
+// Copyright 2013 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_SimpleAverage_h
+#define hifi_SimpleAverage_h
+
+template
+class SimpleAverage {
+public:
+ void update(T sample) {
+ _sum += sample;
+ ++_count;
+ }
+ void reset() {
+ _sum = 0;
+ _count = 0;
+ }
+
+ int getCount() const { return _count; };
+ T getAverage() const { return _sum / (T)_count; };
+
+private:
+ int _count;
+ T _sum;
+};
+
+#endif