Merge branch 'master' of https://github.com/worklist/hifi into audio_select

This commit is contained in:
ZappoMan 2013-07-23 20:20:49 -07:00
commit e7fb392f38
16 changed files with 1139 additions and 64 deletions

View file

@ -77,7 +77,7 @@ include_directories(external/fervor/)
# run qt moc on qt-enabled headers # run qt moc on qt-enabled headers
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/Webcam.h src/avatar/AvatarVoxelSystem.h qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/Webcam.h src/avatar/AvatarVoxelSystem.h
src/avatar/Face.h src/ui/BandwidthDialog.h) src/avatar/Face.h src/ui/BandwidthDialog.h src/ui/VoxelStatsDialog.h)
# create the executable, make it a bundle on OS X # create the executable, make it a bundle on OS X
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS}) add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})

View file

@ -56,6 +56,8 @@
#include <PairingHandler.h> #include <PairingHandler.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <VoxelSceneStats.h>
#include "Application.h" #include "Application.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "LogDisplay.h" #include "LogDisplay.h"
@ -174,6 +176,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_window(new QMainWindow(desktop())), _window(new QMainWindow(desktop())),
_glWidget(new GLCanvas()), _glWidget(new GLCanvas()),
_bandwidthDialog(NULL), _bandwidthDialog(NULL),
_voxelStatsDialog(NULL),
_displayLevels(false), _displayLevels(false),
_frameCount(0), _frameCount(0),
_fps(120.0f), _fps(120.0f),
@ -1147,6 +1150,21 @@ void Application::bandwidthDetailsClosed() {
delete dlg; delete dlg;
} }
void Application::voxelStatsDetails() {
if (!_voxelStatsDialog) {
_voxelStatsDialog = new VoxelStatsDialog(_glWidget, &_voxelSceneStats);
connect(_voxelStatsDialog, SIGNAL(closed()), SLOT(voxelStatsDetailsClosed()));
_voxelStatsDialog->show();
}
_voxelStatsDialog->raise();
}
void Application::voxelStatsDetailsClosed() {
QDialog* dlg = _voxelStatsDialog;
_voxelStatsDialog = NULL;
delete dlg;
}
void Application::editPreferences() { void Application::editPreferences() {
QDialog dialog(_glWidget); QDialog dialog(_glWidget);
dialog.setWindowTitle("Interface Preferences"); dialog.setWindowTitle("Interface Preferences");
@ -1751,6 +1769,7 @@ void Application::initMenu() {
(_bandwidthDisplayOn = toolsMenu->addAction("Bandwidth Display"))->setCheckable(true); (_bandwidthDisplayOn = toolsMenu->addAction("Bandwidth Display"))->setCheckable(true);
_bandwidthDisplayOn->setChecked(true); _bandwidthDisplayOn->setChecked(true);
toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails())); toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails()));
toolsMenu->addAction("Voxel Stats Details", this, SLOT(voxelStatsDetails()));
QMenu* voxelMenu = menuBar->addMenu("Voxels"); QMenu* voxelMenu = menuBar->addMenu("Voxels");
@ -2226,6 +2245,9 @@ void Application::update(float deltaTime) {
if (_bandwidthDialog) { if (_bandwidthDialog) {
_bandwidthDialog->update(); _bandwidthDialog->update();
} }
if (_voxelStatsDialog) {
_voxelStatsDialog->update();
}
// Update audio stats for procedural sounds // Update audio stats for procedural sounds
#ifndef _WIN32 #ifndef _WIN32
@ -2880,27 +2902,19 @@ void Application::displayStats() {
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelStats << "Voxels Created: " << _voxels.getVoxelsCreated() / 1000.f << "K (" << _voxels.getVoxelsCreatedPerSecondAverage() / 1000.f char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
<< "Kps) "; voxelStats << "Voxels Sent from Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelStats << "Voxels Colored: " << _voxels.getVoxelsColored() / 1000.f << "K (" << _voxels.getVoxelsColoredPerSecondAverage() / 1000.f voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
<< "Kps) "; voxelStats << "Scene Send Time from Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str(""); voxelStats.str("");
voxelStats << "Voxel Bits Read: " << _voxels.getVoxelsBytesRead() * 8.f / 1000000.f voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
<< "M (" << _voxels.getVoxelsBytesReadPerSecondAverage() * 8.f / 1000000.f << " Mbps)"; voxelStats << "Encode Time on Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
float voxelsBytesPerColored = _voxels.getVoxelsColored()
? ((float) _voxels.getVoxelsBytesRead() / _voxels.getVoxelsColored())
: 0;
voxelStats << "Voxels Bits per Colored: " << voxelsBytesPerColored * 8;
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
char avatarMixerStats[200]; char avatarMixerStats[200];
@ -3455,16 +3469,37 @@ void* Application::networkReceive(void* args) {
case PACKET_TYPE_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_VOXEL_DATA_MONOCHROME:
case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_Z_COMMAND:
case PACKET_TYPE_ERASE_VOXEL: case PACKET_TYPE_ERASE_VOXEL:
case PACKET_TYPE_VOXEL_STATS:
case PACKET_TYPE_ENVIRONMENT_DATA: { case PACKET_TYPE_ENVIRONMENT_DATA: {
unsigned char* messageData = app->_incomingPacket;
ssize_t messageLength = bytesReceived;
// note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME
// immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first
// then process any remaining bytes as if it was another packet
if (messageData[0] == PACKET_TYPE_VOXEL_STATS) {
int statsMessageLength = app->_voxelSceneStats.unpackFromMessage(messageData, messageLength);
if (messageLength > statsMessageLength) {
messageData += statsMessageLength;
messageLength -= statsMessageLength;
if (!packetVersionMatch(messageData)) {
break; // bail since piggyback data doesn't match our versioning
}
} else {
break; // bail since no piggyback data
}
} // fall through to piggyback message
if (app->_renderVoxels->isChecked()) { if (app->_renderVoxels->isChecked()) {
Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
voxelServer->lock(); voxelServer->lock();
if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { if (messageData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); app->_environment.parseData(&senderAddress, messageData, messageLength);
} else { } else {
app->_voxels.parseData(app->_incomingPacket, bytesReceived); app->_voxels.parseData(messageData, messageLength);
} }
voxelServer->unlock(); voxelServer->unlock();

View file

@ -43,6 +43,7 @@
#include "avatar/HandControl.h" #include "avatar/HandControl.h"
#include "ui/BandwidthDialog.h" #include "ui/BandwidthDialog.h"
#include "ui/ChatEntry.h" #include "ui/ChatEntry.h"
#include "ui/VoxelStatsDialog.h"
class QAction; class QAction;
class QActionGroup; class QActionGroup;
@ -121,6 +122,9 @@ private slots:
void editPreferences(); void editPreferences();
void bandwidthDetailsClosed(); void bandwidthDetailsClosed();
void voxelStatsDetails();
void voxelStatsDetailsClosed();
void pair(); void pair();
void setRenderMirrored(bool mirrored); void setRenderMirrored(bool mirrored);
@ -290,6 +294,7 @@ private:
BandwidthMeter _bandwidthMeter; BandwidthMeter _bandwidthMeter;
BandwidthDialog* _bandwidthDialog; BandwidthDialog* _bandwidthDialog;
VoxelStatsDialog* _voxelStatsDialog;
SerialInterface _serialHeadSensor; SerialInterface _serialHeadSensor;
QNetworkAccessManager* _networkAccessManager; QNetworkAccessManager* _networkAccessManager;
@ -422,6 +427,8 @@ private:
ToolsPalette _palette; ToolsPalette _palette;
Swatch _swatch; Swatch _swatch;
VoxelSceneStats _voxelSceneStats;
}; };
#endif /* defined(__interface__Application__) */ #endif /* defined(__interface__Application__) */

View file

@ -12,6 +12,9 @@
#include <dlfcn.h> // needed for RTLD_LAZY #include <dlfcn.h> // needed for RTLD_LAZY
#include <sstream> #include <sstream>
// Uncomment the next line to use Leap-smoothed stabilized (slower) data.
//#define USE_STABILIZED_DATA
bool LeapManager::_libraryExists = false; bool LeapManager::_libraryExists = false;
bool LeapManager::_doFakeFingers = false; bool LeapManager::_doFakeFingers = false;
Leap::Controller* LeapManager::_controller = NULL; Leap::Controller* LeapManager::_controller = NULL;
@ -175,7 +178,11 @@ void LeapManager::nextFrame(Avatar& avatar) {
finger.resetFramesWithoutData(); finger.resetFramesWithoutData();
finger.setLeapID(leapFinger.id()); finger.setLeapID(leapFinger.id());
finger.setActive(true); finger.setActive(true);
#ifdef USE_STABILIZED_DATA
const Leap::Vector tip = leapFinger.stabilizedTipPosition(); const Leap::Vector tip = leapFinger.stabilizedTipPosition();
#else
const Leap::Vector tip = leapFinger.tipPosition();
#endif
const Leap::Vector root = tip - leapFinger.direction() * leapFinger.length(); const Leap::Vector root = tip - leapFinger.direction() * leapFinger.length();
finger.setRawTipPosition(glm::vec3(tip.x, tip.y, tip.z)); finger.setRawTipPosition(glm::vec3(tip.x, tip.y, tip.z));
finger.setRawRootPosition(glm::vec3(root.x, root.y, root.z)); finger.setRawRootPosition(glm::vec3(root.x, root.y, root.z));

View file

@ -830,13 +830,14 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem
} }
// If there's a leap-interaction hand visible, use that as the endpoint // If there's a leap-interaction hand visible, use that as the endpoint
if (!getHand().isRaveGloveActive()) {
for (size_t i = 0; i < getHand().getPalms().size(); ++i) { for (size_t i = 0; i < getHand().getPalms().size(); ++i) {
PalmData& palm = getHand().getPalms()[i]; PalmData& palm = getHand().getPalms()[i];
if (palm.isActive()) { if (palm.isActive()) {
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition();
} }
} }
}
}//if (_isMine) }//if (_isMine)
//constrain right arm length and re-adjust elbow position as it bends //constrain right arm length and re-adjust elbow position as it bends

View file

@ -0,0 +1,79 @@
//
// VoxelStatsDialog.cpp
// interface
//
// Created by Brad Hefta-Gaub on 7/19/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <QFormLayout>
#include <QDialogButtonBox>
#include <QPalette>
#include <QColor>
#include <VoxelSceneStats.h>
#include "ui/VoxelStatsDialog.h"
VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model) :
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
_model(model) {
char strBuf[64];
this->setWindowTitle("Voxel Statistics");
// Create layouter
QFormLayout* form = new QFormLayout();
this->QDialog::setLayout(form);
// Setup labels
for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; ++i) {
VoxelSceneStats::ItemInfo& itemInfo = _model->getItemInfo(i);
QLabel* label = _labels[i] = new QLabel();
label->setAlignment(Qt::AlignRight);
// Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background)
QPalette palette = label->palette();
unsigned rgb = itemInfo.colorRGBA >> 8;
const unsigned colorpart1 = 0xfefefeu;
const unsigned colorpart2 = 0xf8f8f8;
rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3);
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
label->setPalette(palette);
// This is my hackery attempt at making QDialog auto-size to a width that will hold our info. It kinda works.
label->setText("123456789012345678901234567890123456789012345678901234567890");
snprintf(strBuf, sizeof(strBuf), " %s:", itemInfo.caption);
form->addRow(strBuf, label);
}
}
void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
// Update labels
char strBuf[256];
for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; ++i) {
QLabel* label = _labels[i];
snprintf(strBuf, sizeof(strBuf), "%s", _model->getItemValue(i));
label->setText(strBuf);
}
this->QDialog::paintEvent(event);
this->setFixedSize(this->width(), this->height());
}
void VoxelStatsDialog::reject() {
// Just regularly close upon ESC
this->QDialog::close();
}
void VoxelStatsDialog::closeEvent(QCloseEvent* event) {
this->QDialog::closeEvent(event);
emit closed();
}

View file

@ -0,0 +1,42 @@
//
// VoxelStatsDialog.h
// interface
//
// Created by Brad Hefta-Gaub on 7/19/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__VoxelStatsDialog__
#define __hifi__VoxelStatsDialog__
#include <QDialog>
#include <QLabel>
#include <VoxelSceneStats.h>
class VoxelStatsDialog : public QDialog {
Q_OBJECT
public:
// Sets up the UI
VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model);
signals:
void closed();
public slots:
void reject();
protected:
// State <- data model held by BandwidthMeter
void paintEvent(QPaintEvent*);
// Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent*);
private:
QLabel* _labels[VoxelSceneStats::ITEM_COUNT];
VoxelSceneStats* _model;
};
#endif /* defined(__interface__VoxelStatsDialog__) */

View file

@ -34,6 +34,7 @@ const PACKET_TYPE PACKET_TYPE_TRANSMITTER_DATA_V2 = 'T';
const PACKET_TYPE PACKET_TYPE_ENVIRONMENT_DATA = 'e'; const PACKET_TYPE PACKET_TYPE_ENVIRONMENT_DATA = 'e';
const PACKET_TYPE PACKET_TYPE_DOMAIN_LIST_REQUEST = 'L'; const PACKET_TYPE PACKET_TYPE_DOMAIN_LIST_REQUEST = 'L';
const PACKET_TYPE PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY = 'C'; const PACKET_TYPE PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY = 'C';
const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#';
typedef char PACKET_VERSION; typedef char PACKET_VERSION;

View file

@ -44,6 +44,8 @@ void VoxelNode::init(unsigned char * octalCode) {
_children[i] = NULL; _children[i] = NULL;
} }
_childCount = 0; _childCount = 0;
_subtreeNodeCount = 1; // that's me
_subtreeLeafNodeCount = 0; // that's me
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN; _glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
_isDirty = true; _isDirty = true;
@ -79,6 +81,24 @@ void VoxelNode::handleSubtreeChanged(VoxelTree* myTree) {
if (myTree->getShouldReaverage()) { if (myTree->getShouldReaverage()) {
setColorFromAverageOfChildren(); setColorFromAverageOfChildren();
} }
recalculateSubTreeNodeCount();
}
void VoxelNode::recalculateSubTreeNodeCount() {
// Assuming the tree below me as changed, I need to recalculate my node count
_subtreeNodeCount = 1; // that's me
if (isLeaf()) {
_subtreeLeafNodeCount = 1;
} else {
_subtreeLeafNodeCount = 0;
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (_children[i]) {
_subtreeNodeCount += _children[i]->_subtreeNodeCount;
_subtreeLeafNodeCount += _children[i]->_subtreeLeafNodeCount;
}
}
}
} }

View file

@ -107,6 +107,12 @@ public:
static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL); static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL);
static void removeDeleteHook(int hookID); static void removeDeleteHook(int hookID);
void recalculateSubTreeNodeCount();
unsigned long getSubTreeNodeCount() const { return _subtreeNodeCount; };
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; };
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; };
private: private:
void calculateAABox(); void calculateAABox();
void init(unsigned char * octalCode); void init(unsigned char * octalCode);
@ -126,6 +132,8 @@ private:
unsigned char* _octalCode; unsigned char* _octalCode;
VoxelNode* _children[8]; VoxelNode* _children[8];
int _childCount; int _childCount;
unsigned long _subtreeNodeCount;
unsigned long _subtreeLeafNodeCount;
float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside
static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS];

View file

@ -0,0 +1,556 @@
//
// VoxelSceneStats.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 7/18/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "VoxelNode.h"
#include "VoxelSceneStats.h"
const int samples = 100;
VoxelSceneStats::VoxelSceneStats() :
_elapsedAverage(samples),
_bitsPerVoxelAverage(samples)
{
reset();
_isReadyToSend = false;
_isStarted = false;
}
void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* root) {
reset(); // resets packet and voxel stats
_isStarted = true;
_start = usecTimestampNow();
_totalVoxels = root->getSubTreeNodeCount();
_totalInternal = root->getSubTreeInternalNodeCount();
_totalLeaves = root->getSubTreeLeafNodeCount();
_isFullScene = isFullScene;
_isMoving = isMoving;
}
void VoxelSceneStats::sceneCompleted() {
if (_isStarted) {
_end = usecTimestampNow();
_elapsed = _end - _start;
_elapsedAverage.updateAverage((float)_elapsed);
_statsMessageLength = packIntoMessage(_statsMessage, sizeof(_statsMessage));
_isReadyToSend = true;
_isStarted = false;
}
}
void VoxelSceneStats::encodeStarted() {
_encodeStart = usecTimestampNow();
}
void VoxelSceneStats::encodeStopped() {
_totalEncodeTime += (usecTimestampNow() - _encodeStart);
}
void VoxelSceneStats::reset() {
_totalEncodeTime = 0;
_encodeStart = 0;
_packets = 0;
_bytes = 0;
_passes = 0;
_totalVoxels = 0;
_totalInternal = 0;
_totalLeaves = 0;
_traversed = 0;
_internal = 0;
_leaves = 0;
_skippedDistance = 0;
_internalSkippedDistance = 0;
_leavesSkippedDistance = 0;
_skippedOutOfView = 0;
_internalSkippedOutOfView = 0;
_leavesSkippedOutOfView = 0;
_skippedWasInView = 0;
_internalSkippedWasInView = 0;
_leavesSkippedWasInView = 0;
_skippedNoChange = 0;
_internalSkippedNoChange = 0;
_leavesSkippedNoChange = 0;
_skippedOccluded = 0;
_internalSkippedOccluded = 0;
_leavesSkippedOccluded = 0;
_colorSent = 0;
_internalColorSent = 0;
_leavesColorSent = 0;
_didntFit = 0;
_internalDidntFit = 0;
_leavesDidntFit = 0;
_colorBitsWritten = 0;
_existsBitsWritten = 0;
_existsInPacketBitsWritten = 0;
_treesRemoved = 0;
}
void VoxelSceneStats::packetSent(int bytes) {
_packets++;
_bytes += bytes;
}
void VoxelSceneStats::traversed(const VoxelNode* node) {
_traversed++;
if (node->isLeaf()) {
_leaves++;
} else {
_internal++;
}
}
void VoxelSceneStats::skippedDistance(const VoxelNode* node) {
_skippedDistance++;
if (node->isLeaf()) {
_leavesSkippedDistance++;
} else {
_internalSkippedDistance++;
}
}
void VoxelSceneStats::skippedOutOfView(const VoxelNode* node) {
_skippedOutOfView++;
if (node->isLeaf()) {
_leavesSkippedOutOfView++;
} else {
_internalSkippedOutOfView++;
}
}
void VoxelSceneStats::skippedWasInView(const VoxelNode* node) {
_skippedWasInView++;
if (node->isLeaf()) {
_leavesSkippedWasInView++;
} else {
_internalSkippedWasInView++;
}
}
void VoxelSceneStats::skippedNoChange(const VoxelNode* node) {
_skippedNoChange++;
if (node->isLeaf()) {
_leavesSkippedNoChange++;
} else {
_internalSkippedNoChange++;
}
}
void VoxelSceneStats::skippedOccluded(const VoxelNode* node) {
_skippedOccluded++;
if (node->isLeaf()) {
_leavesSkippedOccluded++;
} else {
_internalSkippedOccluded++;
}
}
void VoxelSceneStats::colorSent(const VoxelNode* node) {
_colorSent++;
if (node->isLeaf()) {
_leavesColorSent++;
} else {
_internalColorSent++;
}
}
void VoxelSceneStats::didntFit(const VoxelNode* node) {
_didntFit++;
if (node->isLeaf()) {
_leavesDidntFit++;
} else {
_internalDidntFit++;
}
}
void VoxelSceneStats::colorBitsWritten() {
_colorBitsWritten++;
}
void VoxelSceneStats::existsBitsWritten() {
_existsBitsWritten++;
}
void VoxelSceneStats::existsInPacketBitsWritten() {
_existsInPacketBitsWritten++;
}
void VoxelSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) {
_existsInPacketBitsWritten--;
if (includesExistsBits) {
_existsBitsWritten--;
}
if (includesColors) {
_colorBitsWritten--;
}
_treesRemoved++;
}
int VoxelSceneStats::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) {
unsigned char* bufferStart = destinationBuffer;
int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_VOXEL_STATS);
destinationBuffer += headerLength;
memcpy(destinationBuffer, &_start, sizeof(_start));
destinationBuffer += sizeof(_start);
memcpy(destinationBuffer, &_end, sizeof(_end));
destinationBuffer += sizeof(_end);
memcpy(destinationBuffer, &_elapsed, sizeof(_elapsed));
destinationBuffer += sizeof(_elapsed);
memcpy(destinationBuffer, &_totalEncodeTime, sizeof(_totalEncodeTime));
destinationBuffer += sizeof(_totalEncodeTime);
memcpy(destinationBuffer, &_isFullScene, sizeof(_isFullScene));
destinationBuffer += sizeof(_isFullScene);
memcpy(destinationBuffer, &_isMoving, sizeof(_isMoving));
destinationBuffer += sizeof(_isMoving);
memcpy(destinationBuffer, &_packets, sizeof(_packets));
destinationBuffer += sizeof(_packets);
memcpy(destinationBuffer, &_bytes, sizeof(_bytes));
destinationBuffer += sizeof(_bytes);
memcpy(destinationBuffer, &_totalInternal, sizeof(_totalInternal));
destinationBuffer += sizeof(_totalInternal);
memcpy(destinationBuffer, &_totalLeaves, sizeof(_totalLeaves));
destinationBuffer += sizeof(_totalLeaves);
memcpy(destinationBuffer, &_internal, sizeof(_internal));
destinationBuffer += sizeof(_internal);
memcpy(destinationBuffer, &_leaves, sizeof(_leaves));
destinationBuffer += sizeof(_leaves);
memcpy(destinationBuffer, &_internalSkippedDistance, sizeof(_internalSkippedDistance));
destinationBuffer += sizeof(_internalSkippedDistance);
memcpy(destinationBuffer, &_leavesSkippedDistance, sizeof(_leavesSkippedDistance));
destinationBuffer += sizeof(_leavesSkippedDistance);
memcpy(destinationBuffer, &_internalSkippedOutOfView, sizeof(_internalSkippedOutOfView));
destinationBuffer += sizeof(_internalSkippedOutOfView);
memcpy(destinationBuffer, &_leavesSkippedOutOfView, sizeof(_leavesSkippedOutOfView));
destinationBuffer += sizeof(_leavesSkippedOutOfView);
memcpy(destinationBuffer, &_internalSkippedWasInView, sizeof(_internalSkippedWasInView));
destinationBuffer += sizeof(_internalSkippedWasInView);
memcpy(destinationBuffer, &_leavesSkippedWasInView, sizeof(_leavesSkippedWasInView));
destinationBuffer += sizeof(_leavesSkippedWasInView);
memcpy(destinationBuffer, &_internalSkippedNoChange, sizeof(_internalSkippedNoChange));
destinationBuffer += sizeof(_internalSkippedNoChange);
memcpy(destinationBuffer, &_leavesSkippedNoChange, sizeof(_leavesSkippedNoChange));
destinationBuffer += sizeof(_leavesSkippedNoChange);
memcpy(destinationBuffer, &_internalSkippedOccluded, sizeof(_internalSkippedOccluded));
destinationBuffer += sizeof(_internalSkippedOccluded);
memcpy(destinationBuffer, &_leavesSkippedOccluded, sizeof(_leavesSkippedOccluded));
destinationBuffer += sizeof(_leavesSkippedOccluded);
memcpy(destinationBuffer, &_internalColorSent, sizeof(_internalColorSent));
destinationBuffer += sizeof(_internalColorSent);
memcpy(destinationBuffer, &_leavesColorSent, sizeof(_leavesColorSent));
destinationBuffer += sizeof(_leavesColorSent);
memcpy(destinationBuffer, &_internalDidntFit, sizeof(_internalDidntFit));
destinationBuffer += sizeof(_internalDidntFit);
memcpy(destinationBuffer, &_leavesDidntFit, sizeof(_leavesDidntFit));
destinationBuffer += sizeof(_leavesDidntFit);
memcpy(destinationBuffer, &_colorBitsWritten, sizeof(_colorBitsWritten));
destinationBuffer += sizeof(_colorBitsWritten);
memcpy(destinationBuffer, &_existsBitsWritten, sizeof(_existsBitsWritten));
destinationBuffer += sizeof(_existsBitsWritten);
memcpy(destinationBuffer, &_existsInPacketBitsWritten, sizeof(_existsInPacketBitsWritten));
destinationBuffer += sizeof(_existsInPacketBitsWritten);
memcpy(destinationBuffer, &_treesRemoved, sizeof(_treesRemoved));
destinationBuffer += sizeof(_treesRemoved);
return destinationBuffer - bufferStart; // includes header!
}
int VoxelSceneStats::unpackFromMessage(unsigned char* sourceBuffer, int availableBytes) {
unsigned char* startPosition = sourceBuffer;
// increment to push past the packet header
int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
sourceBuffer += numBytesPacketHeader;
memcpy(&_start, sourceBuffer, sizeof(_start));
sourceBuffer += sizeof(_start);
memcpy(&_end, sourceBuffer, sizeof(_end));
sourceBuffer += sizeof(_end);
memcpy(&_elapsed, sourceBuffer, sizeof(_elapsed));
sourceBuffer += sizeof(_elapsed);
memcpy(&_totalEncodeTime, sourceBuffer, sizeof(_totalEncodeTime));
sourceBuffer += sizeof(_totalEncodeTime);
memcpy(&_isFullScene, sourceBuffer, sizeof(_isFullScene));
sourceBuffer += sizeof(_isFullScene);
memcpy(&_isMoving, sourceBuffer, sizeof(_isMoving));
sourceBuffer += sizeof(_isMoving);
memcpy(&_packets, sourceBuffer, sizeof(_packets));
sourceBuffer += sizeof(_packets);
memcpy(&_bytes, sourceBuffer, sizeof(_bytes));
sourceBuffer += sizeof(_bytes);
memcpy(&_totalInternal, sourceBuffer, sizeof(_totalInternal));
sourceBuffer += sizeof(_totalInternal);
memcpy(&_totalLeaves, sourceBuffer, sizeof(_totalLeaves));
sourceBuffer += sizeof(_totalLeaves);
_totalVoxels = _totalInternal + _totalLeaves;
memcpy(&_internal, sourceBuffer, sizeof(_internal));
sourceBuffer += sizeof(_internal);
memcpy(&_leaves, sourceBuffer, sizeof(_leaves));
sourceBuffer += sizeof(_leaves);
_traversed = _internal + _leaves;
memcpy(&_internalSkippedDistance, sourceBuffer, sizeof(_internalSkippedDistance));
sourceBuffer += sizeof(_internalSkippedDistance);
memcpy(&_leavesSkippedDistance, sourceBuffer, sizeof(_leavesSkippedDistance));
sourceBuffer += sizeof(_leavesSkippedDistance);
_skippedDistance = _internalSkippedDistance + _leavesSkippedDistance;
memcpy(&_internalSkippedOutOfView, sourceBuffer, sizeof(_internalSkippedOutOfView));
sourceBuffer += sizeof(_internalSkippedOutOfView);
memcpy(&_leavesSkippedOutOfView, sourceBuffer, sizeof(_leavesSkippedOutOfView));
sourceBuffer += sizeof(_leavesSkippedOutOfView);
_skippedOutOfView = _internalSkippedOutOfView + _leavesSkippedOutOfView;
memcpy(&_internalSkippedWasInView, sourceBuffer, sizeof(_internalSkippedWasInView));
sourceBuffer += sizeof(_internalSkippedWasInView);
memcpy(&_leavesSkippedWasInView, sourceBuffer, sizeof(_leavesSkippedWasInView));
sourceBuffer += sizeof(_leavesSkippedWasInView);
_skippedWasInView = _internalSkippedWasInView + _leavesSkippedWasInView;
memcpy(&_internalSkippedNoChange, sourceBuffer, sizeof(_internalSkippedNoChange));
sourceBuffer += sizeof(_internalSkippedNoChange);
memcpy(&_leavesSkippedNoChange, sourceBuffer, sizeof(_leavesSkippedNoChange));
sourceBuffer += sizeof(_leavesSkippedNoChange);
_skippedNoChange = _internalSkippedNoChange + _leavesSkippedNoChange;
memcpy(&_internalSkippedOccluded, sourceBuffer, sizeof(_internalSkippedOccluded));
sourceBuffer += sizeof(_internalSkippedOccluded);
memcpy(&_leavesSkippedOccluded, sourceBuffer, sizeof(_leavesSkippedOccluded));
sourceBuffer += sizeof(_leavesSkippedOccluded);
_skippedOccluded = _internalSkippedOccluded + _leavesSkippedOccluded;
memcpy(&_internalColorSent, sourceBuffer, sizeof(_internalColorSent));
sourceBuffer += sizeof(_internalColorSent);
memcpy(&_leavesColorSent, sourceBuffer, sizeof(_leavesColorSent));
sourceBuffer += sizeof(_leavesColorSent);
_colorSent = _internalColorSent + _leavesColorSent;
memcpy(&_internalDidntFit, sourceBuffer, sizeof(_internalDidntFit));
sourceBuffer += sizeof(_internalDidntFit);
memcpy(&_leavesDidntFit, sourceBuffer, sizeof(_leavesDidntFit));
sourceBuffer += sizeof(_leavesDidntFit);
_didntFit = _internalDidntFit + _leavesDidntFit;
memcpy(&_colorBitsWritten, sourceBuffer, sizeof(_colorBitsWritten));
sourceBuffer += sizeof(_colorBitsWritten);
memcpy(&_existsBitsWritten, sourceBuffer, sizeof(_existsBitsWritten));
sourceBuffer += sizeof(_existsBitsWritten);
memcpy(&_existsInPacketBitsWritten, sourceBuffer, sizeof(_existsInPacketBitsWritten));
sourceBuffer += sizeof(_existsInPacketBitsWritten);
memcpy(&_treesRemoved, sourceBuffer, sizeof(_treesRemoved));
sourceBuffer += sizeof(_treesRemoved);
// running averages
_elapsedAverage.updateAverage((float)_elapsed);
unsigned long total = _existsInPacketBitsWritten + _colorSent;
float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;
_bitsPerVoxelAverage.updateAverage(calculatedBPV);
return sourceBuffer - startPosition; // includes header!
}
void VoxelSceneStats::printDebugDetails() {
qDebug("\n------------------------------\n");
qDebug("VoxelSceneStats:\n");
qDebug(" start : %llu \n", _start);
qDebug(" end : %llu \n", _end);
qDebug(" elapsed : %llu \n", _elapsed);
qDebug(" encoding : %llu \n", _totalEncodeTime);
qDebug("\n");
qDebug(" full scene: %s\n", debug::valueOf(_isFullScene));
qDebug(" moving: %s\n", debug::valueOf(_isMoving));
qDebug("\n");
qDebug(" packets: %d\n", _packets);
qDebug(" bytes : %ld\n", _bytes);
qDebug("\n");
qDebug(" total voxels : %lu\n", _totalVoxels );
qDebug(" internal : %lu\n", _totalInternal );
qDebug(" leaves : %lu\n", _totalLeaves );
qDebug(" traversed : %lu\n", _traversed );
qDebug(" internal : %lu\n", _internal );
qDebug(" leaves : %lu\n", _leaves );
qDebug(" skipped distance : %lu\n", _skippedDistance );
qDebug(" internal : %lu\n", _internalSkippedDistance );
qDebug(" leaves : %lu\n", _leavesSkippedDistance );
qDebug(" skipped out of view : %lu\n", _skippedOutOfView );
qDebug(" internal : %lu\n", _internalSkippedOutOfView );
qDebug(" leaves : %lu\n", _leavesSkippedOutOfView );
qDebug(" skipped was in view : %lu\n", _skippedWasInView );
qDebug(" internal : %lu\n", _internalSkippedWasInView );
qDebug(" leaves : %lu\n", _leavesSkippedWasInView );
qDebug(" skipped no change : %lu\n", _skippedNoChange );
qDebug(" internal : %lu\n", _internalSkippedNoChange );
qDebug(" leaves : %lu\n", _leavesSkippedNoChange );
qDebug(" skipped occluded : %lu\n", _skippedOccluded );
qDebug(" internal : %lu\n", _internalSkippedOccluded );
qDebug(" leaves : %lu\n", _leavesSkippedOccluded );
qDebug("\n");
qDebug(" color sent : %lu\n", _colorSent );
qDebug(" internal : %lu\n", _internalColorSent );
qDebug(" leaves : %lu\n", _leavesColorSent );
qDebug(" Didn't Fit : %lu\n", _didntFit );
qDebug(" internal : %lu\n", _internalDidntFit );
qDebug(" leaves : %lu\n", _leavesDidntFit );
qDebug(" color bits : %lu\n", _colorBitsWritten );
qDebug(" exists bits : %lu\n", _existsBitsWritten );
qDebug(" in packet bit : %lu\n", _existsInPacketBitsWritten);
qDebug(" trees removed : %lu\n", _treesRemoved );
}
const unsigned greenish = 0x40ff40d0;
const unsigned yellowish = 0xffef40c0;
const unsigned greyish = 0xd0d0d0a0;
VoxelSceneStats::ItemInfo VoxelSceneStats::_ITEMS[] = {
{ "Elapsed" , greenish },
{ "Encode" , yellowish },
{ "Network" , greyish },
{ "Voxels on Server" , greenish },
{ "Voxels Sent" , yellowish },
{ "Colors Sent" , greyish },
{ "Bitmasks Sent" , greenish },
{ "Traversed" , yellowish },
{ "Skipped - Total" , greyish },
{ "Skipped - Distance" , greenish },
{ "Skipped - Out of View", yellowish },
{ "Skipped - Was in View", greyish },
{ "Skipped - No Change" , greenish },
{ "Skipped - Occluded" , yellowish },
{ "Didn't fit in packet" , greyish },
{ "Mode" , greenish },
};
char* VoxelSceneStats::getItemValue(int item) {
const uint64_t USECS_PER_SECOND = 1000 * 1000;
int calcFPS, calcAverageFPS, calculatedKBPS;
switch(item) {
case ITEM_ELAPSED: {
calcFPS = (float)USECS_PER_SECOND / (float)_elapsed;
float elapsedAverage = _elapsedAverage.getAverage();
calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage;
sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)",
_elapsed, calcFPS, elapsedAverage, calcAverageFPS);
break;
}
case ITEM_ENCODE:
calcFPS = (float)USECS_PER_SECOND / (float)_totalEncodeTime;
sprintf(_itemValueBuffer, "%llu usecs (%d fps)", _totalEncodeTime, calcFPS);
break;
case ITEM_PACKETS: {
float elapsedSecs = ((float)_elapsed / (float)USECS_PER_SECOND);
calculatedKBPS = elapsedSecs == 0 ? 0 : ((_bytes * 8) / elapsedSecs) / 1000;
sprintf(_itemValueBuffer, "%d packets %lu bytes (%d kbps)", _packets, _bytes, calculatedKBPS);
break;
}
case ITEM_VOXELS_SERVER: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_totalVoxels, _totalInternal, _totalLeaves);
break;
}
case ITEM_VOXELS: {
unsigned long total = _existsInPacketBitsWritten + _colorSent;
float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;
float averageBPV = _bitsPerVoxelAverage.getAverage();
sprintf(_itemValueBuffer, "%lu (%.2f bits/voxel Average: %.2f bits/voxel) %lu internal %lu leaves",
total, calculatedBPV, averageBPV, _existsInPacketBitsWritten, _colorSent);
break;
}
case ITEM_TRAVERSED: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_traversed, _internal, _leaves);
break;
}
case ITEM_SKIPPED: {
unsigned long total = _skippedDistance + _skippedOutOfView +
_skippedWasInView + _skippedNoChange + _skippedOccluded;
unsigned long internal = _internalSkippedDistance + _internalSkippedOutOfView +
_internalSkippedWasInView + _internalSkippedNoChange + _internalSkippedOccluded;
unsigned long leaves = _leavesSkippedDistance + _leavesSkippedOutOfView +
_leavesSkippedWasInView + _leavesSkippedNoChange + _leavesSkippedOccluded;
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
total, internal, leaves);
break;
}
case ITEM_SKIPPED_DISTANCE: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_skippedDistance, _internalSkippedDistance, _leavesSkippedDistance);
break;
}
case ITEM_SKIPPED_OUT_OF_VIEW: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_skippedOutOfView, _internalSkippedOutOfView, _leavesSkippedOutOfView);
break;
}
case ITEM_SKIPPED_WAS_IN_VIEW: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_skippedWasInView, _internalSkippedWasInView, _leavesSkippedWasInView);
break;
}
case ITEM_SKIPPED_NO_CHANGE: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_skippedNoChange, _internalSkippedNoChange, _leavesSkippedNoChange);
break;
}
case ITEM_SKIPPED_OCCLUDED: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_skippedOccluded, _internalSkippedOccluded, _leavesSkippedOccluded);
break;
}
case ITEM_COLORS: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves",
_colorSent, _internalColorSent, _leavesColorSent);
break;
}
case ITEM_DIDNT_FIT: {
sprintf(_itemValueBuffer, "%lu total %lu internal %lu leaves (removed: %lu)",
_didntFit, _internalDidntFit, _leavesDidntFit, _treesRemoved);
break;
}
case ITEM_BITS: {
sprintf(_itemValueBuffer, "colors: %lu, exists: %lu, in packets: %lu",
_colorBitsWritten, _existsBitsWritten, _existsInPacketBitsWritten);
break;
}
case ITEM_MODE: {
sprintf(_itemValueBuffer, "%s - %s", (_isFullScene ? "Full Scene" : "Partial Scene"),
(_isMoving ? "Moving" : "Stationary"));
break;
}
default:
sprintf(_itemValueBuffer, "");
break;
}
return _itemValueBuffer;
}

View file

@ -0,0 +1,170 @@
//
// VoxelSceneStats.h
// hifi
//
// Created by Brad Hefta-Gaub on 7/18/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__VoxelSceneStats__
#define __hifi__VoxelSceneStats__
#include <stdint.h>
#include <NodeList.h>
class VoxelNode;
class VoxelSceneStats {
public:
VoxelSceneStats();
void reset();
void sceneStarted(bool fullScene, bool moving, VoxelNode* root);
void sceneCompleted();
void printDebugDetails();
void packetSent(int bytes);
void encodeStarted();
void encodeStopped();
void traversed(const VoxelNode* node);
void skippedDistance(const VoxelNode* node);
void skippedOutOfView(const VoxelNode* node);
void skippedWasInView(const VoxelNode* node);
void skippedNoChange(const VoxelNode* node);
void skippedOccluded(const VoxelNode* node);
void colorSent(const VoxelNode* node);
void didntFit(const VoxelNode* node);
void colorBitsWritten();
void existsBitsWritten();
void existsInPacketBitsWritten();
void childBitsRemoved(bool includesExistsBits, bool includesColors);
int packIntoMessage(unsigned char* destinationBuffer, int availableBytes);
int unpackFromMessage(unsigned char* sourceBuffer, int availableBytes);
bool isReadyToSend() const { return _isReadyToSend; }
void markAsSent() { _isReadyToSend = false; }
unsigned char* getStatsMessage() { return &_statsMessage[0]; }
int getStatsMessageLength() const { return _statsMessageLength; }
enum {
ITEM_ELAPSED,
ITEM_ENCODE,
ITEM_PACKETS,
ITEM_VOXELS_SERVER,
ITEM_VOXELS,
ITEM_COLORS,
ITEM_BITS,
ITEM_TRAVERSED,
ITEM_SKIPPED,
ITEM_SKIPPED_DISTANCE,
ITEM_SKIPPED_OUT_OF_VIEW,
ITEM_SKIPPED_WAS_IN_VIEW,
ITEM_SKIPPED_NO_CHANGE,
ITEM_SKIPPED_OCCLUDED,
ITEM_DIDNT_FIT,
ITEM_MODE,
ITEM_COUNT
};
// Meta information about each stats item
struct ItemInfo {
char const* const caption;
unsigned colorRGBA;
};
ItemInfo& getItemInfo(int item) { return _ITEMS[item]; };
char* getItemValue(int item);
private:
bool _isReadyToSend;
unsigned char _statsMessage[MAX_PACKET_SIZE];
int _statsMessageLength;
// scene timing data in usecs
bool _isStarted;
uint64_t _start;
uint64_t _end;
uint64_t _elapsed;
SimpleMovingAverage _elapsedAverage;
SimpleMovingAverage _bitsPerVoxelAverage;
uint64_t _totalEncodeTime;
uint64_t _encodeStart;
// scene voxel related data
unsigned long _totalVoxels;
unsigned long _totalInternal;
unsigned long _totalLeaves;
unsigned long _traversed;
unsigned long _internal;
unsigned long _leaves;
unsigned long _skippedDistance;
unsigned long _internalSkippedDistance;
unsigned long _leavesSkippedDistance;
unsigned long _skippedOutOfView;
unsigned long _internalSkippedOutOfView;
unsigned long _leavesSkippedOutOfView;
unsigned long _skippedWasInView;
unsigned long _internalSkippedWasInView;
unsigned long _leavesSkippedWasInView;
unsigned long _skippedNoChange;
unsigned long _internalSkippedNoChange;
unsigned long _leavesSkippedNoChange;
unsigned long _skippedOccluded;
unsigned long _internalSkippedOccluded;
unsigned long _leavesSkippedOccluded;
unsigned long _colorSent;
unsigned long _internalColorSent;
unsigned long _leavesColorSent;
unsigned long _didntFit;
unsigned long _internalDidntFit;
unsigned long _leavesDidntFit;
unsigned long _colorBitsWritten;
unsigned long _existsBitsWritten;
unsigned long _existsInPacketBitsWritten;
unsigned long _treesRemoved;
// Accounting Notes:
//
// 1) number of voxels sent can be calculated as _colorSent + _colorBitsWritten. This works because each internal
// node in a packet will have a _colorBitsWritten included for it and each "leaf" in the packet will have a
// _colorSent written for it. Note that these "leaf" nodes in the packets may not be actual leaves in the full
// tree, because LOD may cause us to send an average color for an internal node instead of recursing deeper to
// the leaves.
//
// 2) the stats balance if: (working assumption)
// if _colorSent > 0
// _traversed = all skipped + _colorSent + _colorBitsWritten
// else
// _traversed = all skipped + _colorSent + _colorBitsWritten + _treesRemoved
//
// scene network related data
unsigned int _packets;
unsigned long _bytes;
unsigned int _passes;
// features related items
bool _isMoving;
bool _isFullScene;
static ItemInfo _ITEMS[];
static int const MAX_ITEM_VALUE_LENGTH = 128;
char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH];
};
#endif /* defined(__hifi__VoxelSceneStats__) */

View file

@ -673,6 +673,9 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
if (hasChildren && !startNode->collapseIdenticalLeaves()) { if (hasChildren && !startNode->collapseIdenticalLeaves()) {
startNode->setColorFromAverageOfChildren(); startNode->setColorFromAverageOfChildren();
} }
// this is also a good time to recalculateSubTreeNodeCount()
startNode->recalculateSubTreeNodeCount();
} }
} }
@ -1037,6 +1040,13 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer,
availableBytes -= codeLength; // keep track or remaining space availableBytes -= codeLength; // keep track or remaining space
int currentEncodeLevel = 0; int currentEncodeLevel = 0;
// record some stats, this is the one node that we won't record below in the recursion function, so we need to
// track it here
if (params.stats) {
params.stats->traversed(node);
}
int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, bag, params, currentEncodeLevel); int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, bag, params, currentEncodeLevel);
// if childBytesWritten == 1 then something went wrong... that's not possible // if childBytesWritten == 1 then something went wrong... that's not possible
@ -1081,6 +1091,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// If we're too far away for our render level, then just return // If we're too far away for our render level, then just return
if (distance >= boundaryDistance) { if (distance >= boundaryDistance) {
if (params.stats) {
params.stats->skippedDistance(node);
}
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1088,6 +1101,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
// we're out of view // we're out of view
if (!node->isInView(*params.viewFrustum)) { if (!node->isInView(*params.viewFrustum)) {
if (params.stats) {
params.stats->skippedOutOfView(node);
}
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1110,6 +1126,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do // if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do
// need to send it. // need to send it.
if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) {
if (params.stats) {
params.stats->skippedWasInView(node);
}
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1117,6 +1136,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// then we can also bail early and save bits // then we can also bail early and save bits
if (!params.forceSendScene && !params.deltaViewFrustum && if (!params.forceSendScene && !params.deltaViewFrustum &&
!node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { !node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) {
if (params.stats) {
params.stats->skippedNoChange(node);
}
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1136,6 +1158,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false);
delete voxelPolygon; // cleanup delete voxelPolygon; // cleanup
if (result == OCCLUDED) { if (result == OCCLUDED) {
if (params.stats) {
params.stats->skippedOccluded(node);
}
return bytesAtThisLevel; return bytesAtThisLevel;
} }
} else { } else {
@ -1201,6 +1226,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
distancesToChildren[i] = 0.0f; distancesToChildren[i] = 0.0f;
currentCount++; currentCount++;
} }
// track stats
if (params.stats && childNode) {
params.stats->traversed(childNode);
}
} }
// for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
@ -1211,13 +1242,21 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum))); bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum)));
if (childIsInView) { if (!childIsInView) {
if (params.stats) {
params.stats->skippedOutOfView(childNode);
}
} else {
// Before we determine consider this further, let's see if it's in our LOD scope... // Before we determine consider this further, let's see if it's in our LOD scope...
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
float boundaryDistance = !params.viewFrustum ? 1 : float boundaryDistance = !params.viewFrustum ? 1 :
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust); boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust);
if (distance < boundaryDistance) { if (!(distance < boundaryDistance)) {
if (params.stats) {
params.stats->skippedDistance(childNode);
}
} else {
inViewCount++; inViewCount++;
// track children in view as existing and not a leaf, if they're a leaf, // track children in view as existing and not a leaf, if they're a leaf,
@ -1261,7 +1300,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
} // wants occlusion culling & isLeaf() } // wants occlusion culling & isLeaf()
bool shouldRender = !params.viewFrustum ? true : childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust); bool shouldRender = !params.viewFrustum
? true
: childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust);
// track some stats
if (params.stats) {
if (!shouldRender && childNode->isLeaf()) {
params.stats->skippedDistance(childNode);
}
if (childIsOccluded) {
params.stats->skippedOccluded(childNode);
}
}
// track children with actual color, only if the child wasn't previously in view! // track children with actual color, only if the child wasn't previously in view!
if (shouldRender && !childIsOccluded) { if (shouldRender && !childIsOccluded) {
@ -1288,7 +1339,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
inViewWithColorCount++; inViewWithColorCount++;
} else { } else {
// otherwise just track stats of the items we discarded // otherwise just track stats of the items we discarded
params.childWasInViewDiscarded++; if (params.stats) {
if (childWasInView) {
params.stats->skippedWasInView(childNode);
} else {
params.stats->skippedNoChange(childNode);
}
}
} }
} }
} }
@ -1297,14 +1355,23 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
*writeToThisLevelBuffer = childrenColoredBits; *writeToThisLevelBuffer = childrenColoredBits;
writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
if (params.stats) {
params.stats->colorBitsWritten();
}
// write the color data... // write the color data...
if (params.includeColor) { if (params.includeColor) {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (oneAtBit(childrenColoredBits, i)) { if (oneAtBit(childrenColoredBits, i)) {
memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); VoxelNode* childNode = node->getChildAtIndex(i);
memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR);
writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color
bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color
if (params.stats) {
params.stats->colorSent(childNode);
}
} }
} }
} }
@ -1315,12 +1382,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
*writeToThisLevelBuffer = childrenExistInTreeBits; *writeToThisLevelBuffer = childrenExistInTreeBits;
writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer
bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count
if (params.stats) {
params.stats->existsBitsWritten();
}
} }
// write the child exist bits // write the child exist bits
*writeToThisLevelBuffer = childrenExistInPacketBits; *writeToThisLevelBuffer = childrenExistInPacketBits;
writeToThisLevelBuffer += sizeof(childrenExistInPacketBits); // move the pointer writeToThisLevelBuffer += sizeof(childrenExistInPacketBits); // move the pointer
bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count
if (params.stats) {
params.stats->existsInPacketBitsWritten();
}
// We only need to keep digging, if there is at least one child that is inView, and not a leaf. // We only need to keep digging, if there is at least one child that is inView, and not a leaf.
keepDiggingDeeper = (inViewNotLeafCount > 0); keepDiggingDeeper = (inViewNotLeafCount > 0);
@ -1333,6 +1406,11 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
availableBytes -= bytesAtThisLevel; availableBytes -= bytesAtThisLevel;
} else { } else {
bag.insert(node); bag.insert(node);
if (params.stats) {
params.stats->didntFit(node);
}
return 0; return 0;
} }
@ -1393,7 +1471,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!!
// //
// we can make this act like no bytes out, by just resetting the bytes out in this case // we can make this act like no bytes out, by just resetting the bytes out in this case
if (params.includeColor && childTreeBytesOut == 2) { if (params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) {
childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees
}
// If we've asked for existBits, this is also true, except that the tree will output 3 bytes
// NOTE: does this introduce a problem with detecting deletion??
if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) {
childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees
} }
@ -1408,6 +1491,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
childrenExistInPacketBits -= (1 << (7 - originalIndex)); childrenExistInPacketBits -= (1 << (7 - originalIndex));
// repair the child exists mask // repair the child exists mask
*childExistsPlaceHolder = childrenExistInPacketBits; *childExistsPlaceHolder = childrenExistInPacketBits;
// If this is the last of the child exists bits, then we're actually be rolling out the entire tree
if (params.stats && childrenExistInPacketBits == 0) {
params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor);
}
// Note: no need to move the pointer, cause we already stored this // Note: no need to move the pointer, cause we already stored this
} // end if (childTreeBytesOut == 0) } // end if (childTreeBytesOut == 0)
} // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex))

View file

@ -9,12 +9,14 @@
#ifndef __hifi__VoxelTree__ #ifndef __hifi__VoxelTree__
#define __hifi__VoxelTree__ #define __hifi__VoxelTree__
#include "SimpleMovingAverage.h" #include <PointerStack.h>
#include <SimpleMovingAverage.h>
#include "CoverageMap.h"
#include "ViewFrustum.h" #include "ViewFrustum.h"
#include "VoxelNode.h" #include "VoxelNode.h"
#include "VoxelNodeBag.h" #include "VoxelNodeBag.h"
#include "CoverageMap.h" #include "VoxelSceneStats.h"
#include "PointerStack.h"
// Callback function, for recuseTreeWithOperation // Callback function, for recuseTreeWithOperation
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
@ -36,6 +38,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define NO_BOUNDARY_ADJUST 0 #define NO_BOUNDARY_ADJUST 0
#define LOW_RES_MOVING_ADJUST 1 #define LOW_RES_MOVING_ADJUST 1
#define IGNORE_LAST_SENT 0 #define IGNORE_LAST_SENT 0
#define IGNORE_SCENE_STATS NULL
class EncodeBitstreamParams { class EncodeBitstreamParams {
public: public:
@ -48,10 +51,10 @@ public:
bool deltaViewFrustum; bool deltaViewFrustum;
const ViewFrustum* lastViewFrustum; const ViewFrustum* lastViewFrustum;
bool wantOcclusionCulling; bool wantOcclusionCulling;
long childWasInViewDiscarded;
int boundaryLevelAdjust; int boundaryLevelAdjust;
uint64_t lastViewFrustumSent; uint64_t lastViewFrustumSent;
bool forceSendScene; bool forceSendScene;
VoxelSceneStats* stats;
CoverageMap* map; CoverageMap* map;
EncodeBitstreamParams( EncodeBitstreamParams(
@ -66,7 +69,8 @@ public:
CoverageMap* map = IGNORE_COVERAGE_MAP, CoverageMap* map = IGNORE_COVERAGE_MAP,
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST,
uint64_t lastViewFrustumSent = IGNORE_LAST_SENT, uint64_t lastViewFrustumSent = IGNORE_LAST_SENT,
bool forceSendScene = true) : bool forceSendScene = true,
VoxelSceneStats* stats = IGNORE_SCENE_STATS) :
maxEncodeLevel (maxEncodeLevel), maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0), maxLevelReached (0),
viewFrustum (viewFrustum), viewFrustum (viewFrustum),
@ -76,10 +80,10 @@ public:
deltaViewFrustum (deltaViewFrustum), deltaViewFrustum (deltaViewFrustum),
lastViewFrustum (lastViewFrustum), lastViewFrustum (lastViewFrustum),
wantOcclusionCulling (wantOcclusionCulling), wantOcclusionCulling (wantOcclusionCulling),
childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust), boundaryLevelAdjust (boundaryLevelAdjust),
lastViewFrustumSent (lastViewFrustumSent), lastViewFrustumSent (lastViewFrustumSent),
forceSendScene (forceSendScene), forceSendScene (forceSendScene),
stats (stats),
map (map) map (map)
{} {}
}; };

View file

@ -12,9 +12,11 @@
#include <iostream> #include <iostream>
#include <NodeData.h> #include <NodeData.h>
#include <AvatarData.h> #include <AvatarData.h>
#include "VoxelNodeBag.h"
#include "VoxelConstants.h" #include <CoverageMap.h>
#include "CoverageMap.h" #include <VoxelConstants.h>
#include <VoxelNodeBag.h>
#include <VoxelSceneStats.h>
class VoxelNodeData : public AvatarData { class VoxelNodeData : public AvatarData {
public: public:
@ -58,6 +60,9 @@ public:
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; };
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; }; bool getCurrentPacketIsColor() const { return _currentPacketIsColor; };
VoxelSceneStats stats;
private: private:
VoxelNodeData(const VoxelNodeData &); VoxelNodeData(const VoxelNodeData &);
VoxelNodeData& operator= (const VoxelNodeData&); VoxelNodeData& operator= (const VoxelNodeData&);

View file

@ -60,6 +60,7 @@ bool wantLocalDomain = false;
bool wantColorRandomizer = false; bool wantColorRandomizer = false;
bool debugVoxelSending = false; bool debugVoxelSending = false;
bool shouldShowAnimationDebug = false; bool shouldShowAnimationDebug = false;
bool displayVoxelStats = false;
EnvironmentData environmentData[3]; EnvironmentData environmentData[3];
@ -111,6 +112,44 @@ void eraseVoxelTreeAndCleanupNodeVisitData() {
pthread_mutex_t treeLock; pthread_mutex_t treeLock;
void handlePacketSend(NodeList* nodeList,
NodeList::iterator& node,
VoxelNodeData* nodeData,
int& trueBytesSent, int& truePacketsSent) {
// If we've got a stats message ready to send, then see if we can piggyback them together
if (nodeData->stats.isReadyToSend()) {
// Send the stats message to the client
unsigned char* statsMessage = nodeData->stats.getStatsMessage();
int statsMessageLength = nodeData->stats.getStatsMessageLength();
// If the size of the stats message and the voxel message will fit in a packet, then piggyback them
if (nodeData->getPacketLength() + statsMessageLength < MAX_PACKET_SIZE) {
// copy voxel message to back of stats message
memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength());
statsMessageLength += nodeData->getPacketLength();
// actually send it
nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength);
} else {
// not enough room in the packet, send two packets
nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength);
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
}
} else {
// just send the voxel packet
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
}
// remember to track our stats
nodeData->stats.packetSent(nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();
}
// Version of voxel distributor that sends the deepest LOD level at once // Version of voxel distributor that sends the deepest LOD level at once
void deepestLevelVoxelDistributor(NodeList* nodeList, void deepestLevelVoxelDistributor(NodeList* nodeList,
NodeList::iterator& node, NodeList::iterator& node,
@ -141,11 +180,9 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
} }
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength()); handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();
} else { } else {
if (::debugVoxelSending) { if (::debugVoxelSending) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
@ -200,13 +237,20 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
// only set our last sent time if we weren't resetting due to frustum change // only set our last sent time if we weren't resetting due to frustum change
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
nodeData->setLastTimeBagEmpty(now); nodeData->setLastTimeBagEmpty(now);
if (::debugVoxelSending) {
printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now);
} }
nodeData->stats.sceneCompleted();
if (::displayVoxelStats) {
nodeData->stats.printDebugDetails();
} }
// This is the start of "resending" the scene. // This is the start of "resending" the scene.
nodeData->nodeBag.insert(serverTree.rootNode); nodeData->nodeBag.insert(serverTree.rootNode);
// start tracking our stats
bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging();
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, ::serverTree.rootNode);
} }
// If we have something in our nodeBag, then turn them into packets and send them out... // If we have something in our nodeBag, then turn them into packets and send them out...
@ -240,32 +284,31 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving() int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving()
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST; ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST;
bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) &&
nodeData->getViewFrustumJustStoppedChanging();
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
nodeData->getLastTimeBagEmpty(), nodeData->getLastTimeBagEmpty(),
nodeData->getViewFrustumJustStoppedChanging()); isFullScene, &nodeData->stats);
nodeData->stats.encodeStarted();
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params); nodeData->nodeBag, params);
nodeData->stats.encodeStopped();
if (nodeData->getAvailable() >= bytesWritten) { if (nodeData->getAvailable() >= bytesWritten) {
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten); nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
} else { } else {
nodeList->getNodeSocket()->send(node->getActiveSocket(), handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);
nodeData->getPacket(), nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
packetsSentThisInterval++; packetsSentThisInterval++;
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten); nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
} }
} else { } else {
if (nodeData->isPacketWaiting()) { if (nodeData->isPacketWaiting()) {
nodeList->getNodeSocket()->send(node->getActiveSocket(), handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);
nodeData->getPacket(), nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
} }
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
@ -368,9 +411,11 @@ void *distributeVoxelsToListeners(void *args) {
if (usecToSleep > 0) { if (usecToSleep > 0) {
usleep(usecToSleep); usleep(usecToSleep);
} else { } else {
if (::debugVoxelSending) {
std::cout << "Last send took too much time, not sleeping!\n"; std::cout << "Last send took too much time, not sleeping!\n";
} }
} }
}
pthread_exit(0); pthread_exit(0);
} }
@ -402,6 +447,10 @@ int main(int argc, const char * argv[]) {
srand((unsigned)time(0)); srand((unsigned)time(0));
const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
::displayVoxelStats = cmdOptionExists(argc, argv, DISPLAY_VOXEL_STATS);
printf("displayVoxelStats=%s\n", debug::valueOf(::displayVoxelStats));
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING); ::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING);
printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending)); printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending));
@ -437,8 +486,10 @@ int main(int argc, const char * argv[]) {
::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it ::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
unsigned long nodeCount = ::serverTree.getVoxelCount(); unsigned long nodeCount = ::serverTree.rootNode->getSubTreeNodeCount();
printf("Nodes after loading scene %ld nodes\n", nodeCount); unsigned long internalNodeCount = ::serverTree.rootNode->getSubTreeInternalNodeCount();
unsigned long leafNodeCount = ::serverTree.rootNode->getSubTreeLeafNodeCount();
printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
} }
// Check to see if the user passed in a command line option for loading an old style local // Check to see if the user passed in a command line option for loading an old style local