From c2cb6df61cc4758cf6087f4123100ce1e1d98d94 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 18 Nov 2013 09:46:32 -0800 Subject: [PATCH 01/77] first cut at compresses voxel packets --- interface/src/VoxelPacketProcessor.cpp | 14 +++- interface/src/VoxelSystem.cpp | 4 +- .../src/VoxelNodeData.cpp | 64 +++++++++++++++++-- .../voxel-server-library/src/VoxelNodeData.h | 14 ++-- .../src/VoxelSendThread.cpp | 43 ++++++++++++- 5 files changed, 123 insertions(+), 16 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 9087a5a545..18f71ccd6a 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -8,6 +8,8 @@ // Threaded or non-threaded voxel packet receiver for the Application // +#include + #include #include "Application.h" @@ -56,7 +58,17 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* app->_environment.parseData(&senderAddress, packetData, messageLength); } else { app->_voxels.setDataSourceUUID(voxelServer->getUUID()); - app->_voxels.parseData(packetData, messageLength); + + // thse packets are commpressed... + + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + QByteArray compressedData((const char*)packetData + numBytesPacketHeader, + messageLength - numBytesPacketHeader); + QByteArray uncompressedData = qUncompress(compressedData); + QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); + uncompressedPacket.append(uncompressedData); + + app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); app->_voxels.setDataSourceUUID(QUuid()); } } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 62419565c6..acbd4b3024 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -595,7 +595,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, NULL, getDataSourceUUID()); lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); unlockTree(); @@ -605,7 +605,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree - ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); + ReadBitstreamToTreeParams args(NO_COLOR, NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, NULL, getDataSourceUUID()); lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); unlockTree(); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 12f444b454..8dce11fb5d 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -13,10 +13,12 @@ #include #include "VoxelSendThread.h" +const int UNCOMPRESSED_SIZE_MULTIPLE = 20; + VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelQuery(owningNode), _viewSent(false), - _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), + _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE), _maxSearchLevel(1), _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), @@ -29,9 +31,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lodChanged(false), _lodInitialized(false) { - _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE]; _voxelPacketAt = _voxelPacket; - _lastVoxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + _lastVoxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE]; _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; resetVoxelPacket(); @@ -44,9 +46,9 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { _voxelSendThread->initialize(true); } -bool VoxelNodeData::packetIsDuplicate() const { +bool VoxelNodeData::packetIsDuplicate() { if (_lastVoxelPacketLength == getPacketLength()) { - return memcmp(_lastVoxelPacket, _voxelPacket, getPacketLength()) == 0; + return memcmp(_lastVoxelPacket, getPacket(), getPacketLength()) == 0; } return false; } @@ -91,7 +93,7 @@ void VoxelNodeData::resetVoxelPacket() { // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. _lastVoxelPacketLength = getPacketLength(); - memcpy(_lastVoxelPacket, _voxelPacket, _lastVoxelPacketLength); + memcpy(_lastVoxelPacket, getPacket(), _lastVoxelPacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. @@ -100,15 +102,63 @@ void VoxelNodeData::resetVoxelPacket() { int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; + _voxelPacketAvailableBytes = (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - numBytesPacketHeader; + compressPacket(); _voxelPacketWaiting = false; } +bool VoxelNodeData::willFit(unsigned char* buffer, int bytes) { + int uncompressedLength = getPacketLengthUncompressed(); + const int MAX_COMPRESSION = 9; + // we only want to compress the data payload, not the message header + int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); + + // start with the current uncompressed data + QByteArray uncompressedTestData((const char*)_voxelPacket + numBytesPacketHeader, + uncompressedLength - numBytesPacketHeader); + + // append this next buffer... + uncompressedTestData.append((const char*)buffer, bytes); + + // test compress it + QByteArray compressedData = qCompress(uncompressedTestData, MAX_COMPRESSION); + + bool wouldFit = (compressedData.size() + numBytesPacketHeader) <= MAX_VOXEL_PACKET_SIZE; + + /* + if (!wouldFit) { + printf("would not fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", + getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + } else { + printf("would fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", + getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + } + */ + return wouldFit; +} + void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; _voxelPacketWaiting = true; + compressPacket(); +} + +int VoxelNodeData::getPacketLengthUncompressed() const { + return (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - _voxelPacketAvailableBytes; +} + +void VoxelNodeData::compressPacket() { + int uncompressedLength = getPacketLengthUncompressed(); + const int MAX_COMPRESSION = 9; + // we only want to compress the data payload, not the message header + int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); + QByteArray compressedData = qCompress(_voxelPacket+numBytesPacketHeader, + uncompressedLength-numBytesPacketHeader, MAX_COMPRESSION); + _compressedPacket.clear(); + _compressedPacket.append((const char*)_voxelPacket, numBytesPacketHeader); + _compressedPacket.append(compressedData); } VoxelNodeData::~VoxelNodeData() { diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index c21b99a308..ad928280d5 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -29,15 +29,18 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet + bool willFit(unsigned char* buffer, int bytes); // tests to see if the bytes will fit + + const unsigned char* getPacket() const { return (const unsigned char*)_compressedPacket.constData(); } + int getPacketLength() const { return _compressedPacket.size(); } + int getPacketLengthUncompressed() const; - const unsigned char* getPacket() const { return _voxelPacket; } - int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } - bool packetIsDuplicate() const; + bool packetIsDuplicate(); bool shouldSuppressDuplicatePacket(); - int getAvailable() const { return _voxelPacketAvailableBytes; } + int getAvailable() const { return MAX_VOXEL_PACKET_SIZE - getPacketLength(); } int getMaxSearchLevel() const { return _maxSearchLevel; }; void resetMaxSearchLevel() { _maxSearchLevel = 1; }; void incrementMaxSearchLevel() { _maxSearchLevel++; }; @@ -109,6 +112,9 @@ private: float _lastClientVoxelSizeScale; bool _lodChanged; bool _lodInitialized; + + QByteArray _compressedPacket; + void compressPacket(); }; #endif /* defined(__hifi__VoxelNodeData__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index fe2842d6d7..ee6262ca13 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -78,6 +78,11 @@ bool VoxelSendThread::process() { } +int totalUncompressed = 0; +int totalCompressed = 0; +int totalWastedBytes = 0; +int totalPackets = 0; + int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { int packetsSent = 0; @@ -102,6 +107,17 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); statsMessageLength += nodeData->getPacketLength(); + int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + ::totalWastedBytes += thisWastedBytes; + ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalCompressed += nodeData->getPacketLength(); + ::totalPackets++; + qDebug("Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); + // actually send it NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); } else { @@ -113,12 +129,34 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), nodeData->getPacket(), nodeData->getPacketLength()); + + int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + ::totalWastedBytes += thisWastedBytes; + ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalCompressed += nodeData->getPacketLength(); + ::totalPackets++; + qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); } nodeData->stats.markAsSent(); } else { // just send the voxel packet NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), nodeData->getPacket(), nodeData->getPacketLength()); + + int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + ::totalWastedBytes += thisWastedBytes; + ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalCompressed += nodeData->getPacketLength(); + ::totalPackets++; + qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); } // remember to track our stats nodeData->stats.packetSent(nodeData->getPacketLength()); @@ -297,7 +335,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, - WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, + NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, DONT_CHOP, wantDelta, lastViewFrustum, wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); @@ -310,7 +348,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); - if (nodeData->getAvailable() >= bytesWritten) { + // NOTE: could be better, the bytesWritten might be compressable... + if (nodeData->willFit(_tempOutputBuffer, bytesWritten)) { nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); From 8c90e9674000164415788799345af4e50d871849 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 19 Nov 2013 15:36:21 -0800 Subject: [PATCH 02/77] addeding VoxelPacket class for encoding bit streams --- .../src/VoxelSendThread.cpp | 9 +- .../src/VoxelSendThread.h | 1 + libraries/voxels/src/VoxelPacket.cpp | 101 +++++++++++++ libraries/voxels/src/VoxelPacket.h | 55 +++++++ libraries/voxels/src/VoxelTree.cpp | 143 +++++++++++------- libraries/voxels/src/VoxelTree.h | 5 +- 6 files changed, 250 insertions(+), 64 deletions(-) create mode 100644 libraries/voxels/src/VoxelPacket.cpp create mode 100644 libraries/voxels/src/VoxelPacket.h diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index ee6262ca13..6c3bdd07cc 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -343,17 +343,18 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, + _tempPacket.reset(); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); // NOTE: could be better, the bytesWritten might be compressable... - if (nodeData->willFit(_tempOutputBuffer, bytesWritten)) { - nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); + if (nodeData->willFit(_tempPacket.getStartOfBuffer(), bytesWritten)) { + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), bytesWritten); } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), bytesWritten); } } else { if (nodeData->isPacketWaiting()) { diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 63c68e7cbe..7283a570a1 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -34,6 +34,7 @@ private: int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged); unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; + VoxelPacket _tempPacket; }; #endif // __voxel_server__VoxelSendThread__ diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp new file mode 100644 index 0000000000..109847ffe6 --- /dev/null +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -0,0 +1,101 @@ +// +// VoxelPacket.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 11/19/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "VoxelPacket.h" + +VoxelPacket::VoxelPacket() { + reset(); +} + +void VoxelPacket::reset() { + _bytesInUse = 0; + _bytesAvailable = MAX_VOXEL_PACKET_SIZE; + _subTreeAt = 0; + _levelAt = 0; +} + +VoxelPacket::~VoxelPacket() { +} + +bool VoxelPacket::append(const unsigned char* data, int length) { + bool success = false; + + if (length <= _bytesAvailable) { + memcpy(&_buffer[_bytesInUse], data, length); + _bytesInUse += length; + _bytesAvailable -= length; + success = true; + } + return success; +} + +bool VoxelPacket::setByte(int offset, unsigned char byte) { + bool success = false; + if (offset >= 0 && offset < _bytesInUse) { + _buffer[offset] = byte; + success = true; + } + return success; +} + + + +void VoxelPacket::startSubTree(const unsigned char* octcode) { + _subTreeAt = _bytesInUse; + if (octcode) { + int length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode)); + append(octcode, length); + } else { + // NULL case, means root node, which is 0 + _buffer[_bytesInUse] = 0; + _bytesInUse += 1; + _bytesAvailable -= 1; + } +} + +void VoxelPacket::endSubTree() { + _subTreeAt = _bytesInUse; +} + +void VoxelPacket::discardSubTree() { + int bytesInSubTree = _bytesInUse - _subTreeAt; + _bytesInUse -= bytesInSubTree; + _bytesAvailable += bytesInSubTree; +} + +void VoxelPacket::startLevel() { + _levelAt = _bytesInUse; +} + +bool VoxelPacket::appendBitMask(unsigned char bitmask) { + bool success = false; + if (_bytesAvailable > 0) { + _buffer[_bytesInUse] = bitmask; + success = true; + } + return success; +} + +bool VoxelPacket::appendColor(rgbColor color) { + // eventually we can make this use a dictionary... + bool success = false; + if (_bytesAvailable > sizeof(rgbColor)) { + success = append((const unsigned char*)&color, sizeof(rgbColor)); + } + return success; +} + +void VoxelPacket::endLevel() { + _levelAt = _bytesInUse; +} + +void VoxelPacket::discardLevel() { + int bytesInLevel = _bytesInUse - _levelAt; + _bytesInUse -= bytesInLevel; + _bytesAvailable += bytesInLevel; +} diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h new file mode 100644 index 0000000000..3aac7ac2a2 --- /dev/null +++ b/libraries/voxels/src/VoxelPacket.h @@ -0,0 +1,55 @@ +// +// VoxelPacket.h +// hifi +// +// Created by Brad Hefta-Gaub on 11/19/2013 +// +// + +#ifndef __hifi__VoxelPacket__ +#define __hifi__VoxelPacket__ + +#include +#include "VoxelConstants.h" +#include "VoxelNode.h" + +class VoxelPacket { +public: + VoxelPacket(); + ~VoxelPacket(); + + void reset(); + void startSubTree(const unsigned char* octcode = NULL); + void endSubTree(); + void discardSubTree(); + + void startLevel(); + bool appendBitMask(unsigned char bitmask); + bool appendColor(rgbColor color); + void discardLevel(); + void endLevel(); + + bool append(const unsigned char* data, int length); /// appends raw bytes + bool setByte(int offset, unsigned char byte); /// sets a single raw byte from previously appended portion of the stream + int getBytesInUse() const { return _bytesInUse; } + int getBytesAvailable() const { return _bytesAvailable; } + + /// returns a byte offset from beginning of stream based on offset from end. + /// Positive offsetFromEnd returns that many bytes before the end + int getByteOffset(int offsetFromEnd) const { + return _bytesInUse - offsetFromEnd; + } + + unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to current end of stream buffer + unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer + + +private: + unsigned char _buffer[MAX_VOXEL_PACKET_SIZE]; + int _bytesInUse; + int _bytesAvailable; + int _subTreeAt; + int _levelAt; +}; + +#endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2681742437..8c6f2128a4 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1020,7 +1020,7 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& return args.found; } -int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, +int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) { // How many bytes have we written so far at this level; @@ -1044,22 +1044,17 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int codeLength; if (params.chopLevels) { unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); + packet->startSubTree(newCode); if (newCode) { codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); - memcpy(outputBuffer, newCode, codeLength); - delete newCode; } else { - codeLength = 1; // chopped to root! - *outputBuffer = 0; // root + codeLength = 1; } } else { + packet->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); - memcpy(outputBuffer, node->getOctalCode(), codeLength); } - - outputBuffer += codeLength; // move the pointer bytesWritten += codeLength; // keep track of byte count - availableBytes -= codeLength; // keep track or remaining space int currentEncodeLevel = 0; @@ -1069,7 +1064,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, bag, params, currentEncodeLevel); + int childBytesWritten = encodeTreeBitstreamRecursion(node, packet, bag, params, currentEncodeLevel); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -1088,11 +1083,15 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, bytesWritten = 0; } + if (bytesWritten == 0) { + packet->discardSubTree(); + } + doneEncoding(node); return bytesWritten; } -int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, +int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const { // How many bytes have we written so far at this level; @@ -1235,14 +1234,15 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp unsigned char childrenExistInPacketBits = 0; unsigned char childrenColoredBits = 0; - const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); + //const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); const int BYTES_PER_COLOR = 3; - const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); - const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + //const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); + //const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; // Make our local buffer large enough to handle writing at this level in case we need to. - unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; - unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + //unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; + //unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + packet->startLevel(); int inViewCount = 0; int inViewNotLeafCount = 0; @@ -1423,20 +1423,38 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } } - *writeToThisLevelBuffer = childrenColoredBits; - writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer - bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count - if (params.stats) { - params.stats->colorBitsWritten(); + //*writeToThisLevelBuffer = childrenColoredBits; + //writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer + + bool continueThisLevel = true; + continueThisLevel = packet->appendBitMask(childrenColoredBits); + + if (continueThisLevel) { + bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count + if (params.stats) { + params.stats->colorBitsWritten(); + } } // write the color data... - if (params.includeColor) { + if (continueThisLevel && params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { VoxelNode* childNode = node->getChildAtIndex(i); - memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR); - writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + + rgbColor color; + color[0] = childNode->getColor()[0]; + color[1] = childNode->getColor()[1]; + color[2] = childNode->getColor()[2]; + continueThisLevel = packet->appendColor(color); + + if (!continueThisLevel) { + break; // no point in continuing + } + + //memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR); + //writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color // don't need to check childNode here, because we can't get here with no childNode @@ -1450,32 +1468,43 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits - if (params.includeExistsBits) { - *writeToThisLevelBuffer = childrenExistInTreeBits; - writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer - bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count - if (params.stats) { - params.stats->existsBitsWritten(); + if (continueThisLevel && params.includeExistsBits) { + //*writeToThisLevelBuffer = childrenExistInTreeBits; + //writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer + + continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); + + if (continueThisLevel) { + bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count + if (params.stats) { + params.stats->existsBitsWritten(); + } } } // write the child exist bits - *writeToThisLevelBuffer = childrenExistInPacketBits; - bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count - if (params.stats) { - params.stats->existsInPacketBitsWritten(); + if (continueThisLevel) { + continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); + //*writeToThisLevelBuffer = childrenExistInPacketBits; + 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. keepDiggingDeeper = (inViewNotLeafCount > 0); // If we have enough room to copy our local results into the buffer, then do so... - if (availableBytes >= bytesAtThisLevel) { - memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); - - outputBuffer += bytesAtThisLevel; - availableBytes -= bytesAtThisLevel; - } else { + //int availableBytes = packet->getBytesAvailable(); + //if (availableBytes >= bytesAtThisLevel) { + // packet->append(&thisLevelBuffer[0], bytesAtThisLevel); + //} else { + + // if we were unable to fit this level in our packet, then rewind and add it to the node bag for + // sending later... + if (!continueThisLevel) { + packet->discardLevel(); bag.insert(node); // don't need to check node here, because we can't get here with no node @@ -1496,8 +1525,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // write our childExistsBits as a place holder. Then let each potential tree have a go at it. If they // write something, we keep them in the bits, if they don't, we take them out. // - // we know the last thing we wrote to the outputBuffer was our childrenExistInPacketBits. Let's remember where that was! - unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistInPacketBits); + // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! + int childExistsPlaceHolder = packet->getByteOffset(sizeof(childrenExistInPacketBits)); // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, @@ -1505,7 +1534,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // a single recursive pass in distance sorted order, but retain standard order in our encoded packet int recursiveSliceSizes[NUMBER_OF_CHILDREN]; unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - unsigned char* firstRecursiveSlice = outputBuffer; + unsigned char* firstRecursiveSlice = packet->getEndOfBuffer(); int allSlicesSize = 0; // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so @@ -1518,9 +1547,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp int thisLevel = currentEncodeLevel; // remember this for reshuffling - recursiveSliceStarts[originalIndex] = outputBuffer; + recursiveSliceStarts[originalIndex] = packet->getEndOfBuffer(); - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, outputBuffer, availableBytes, bag, + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); // remember this for reshuffling @@ -1555,8 +1584,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp //} bytesAtThisLevel += childTreeBytesOut; - availableBytes -= childTreeBytesOut; - outputBuffer += childTreeBytesOut; // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask @@ -1564,7 +1591,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // remove this child's bit... childrenExistInPacketBits -= (1 << (7 - originalIndex)); // repair the child exists mask - *childExistsPlaceHolder = childrenExistInPacketBits; + packet->setByte(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) { @@ -1806,7 +1833,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { nodeBag.insert(rootNode); } - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + static VoxelPacket packet; int bytesWritten = 0; while (!nodeBag.isEmpty()) { @@ -1814,9 +1841,9 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); unlock(); - file.write((const char*)&outputBuffer[0], bytesWritten); + file.write((const char*)packet.getStartOfBuffer(), bytesWritten); } } file.close(); @@ -1841,7 +1868,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); } - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + static VoxelPacket packet; int bytesWritten = 0; while (!nodeBag.isEmpty()) { @@ -1849,11 +1876,11 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); - bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); - destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, args); + destinationTree->readBitstreamToTree(packet.getStartOfBuffer(), bytesWritten, args); } VoxelNode* destinationStartNode; @@ -1870,7 +1897,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + static VoxelPacket packet; int bytesWritten = 0; while (!nodeBag.isEmpty()) { @@ -1878,12 +1905,12 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); + bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packet, nodeBag, params); // ask destination tree to read the bitstream bool wantImportProgress = true; ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress); - readBitstreamToTree(&outputBuffer[0], bytesWritten, args); + readBitstreamToTree(packet.getStartOfBuffer(), bytesWritten, args); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index f8e0458fa1..af92fcebcd 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -17,6 +17,7 @@ #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" +#include "VoxelPacket.h" #include "VoxelSceneStats.h" #include "VoxelEditPacketSender.h" @@ -163,7 +164,7 @@ public: void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData=NULL); - int encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + int encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } @@ -221,7 +222,7 @@ private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); - int encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + int encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const; static bool countVoxelsOperation(VoxelNode* node, void* extraData); From 6c640752cdc24c4e5e7d5baba209e8dd4db7d4fc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 12:04:13 -0800 Subject: [PATCH 03/77] make compression optional --- interface/src/VoxelPacketProcessor.cpp | 21 +++--- interface/src/VoxelSystem.cpp | 4 +- .../src/VoxelNodeData.cpp | 71 +++++++++++++------ .../voxel-server-library/src/VoxelNodeData.h | 4 +- .../src/VoxelSendThread.cpp | 2 +- libraries/voxels/src/VoxelConstants.h | 1 + 6 files changed, 67 insertions(+), 36 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 18f71ccd6a..52f992d56b 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -59,16 +59,19 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* } else { app->_voxels.setDataSourceUUID(voxelServer->getUUID()); - // thse packets are commpressed... - - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - QByteArray compressedData((const char*)packetData + numBytesPacketHeader, - messageLength - numBytesPacketHeader); - QByteArray uncompressedData = qUncompress(compressedData); - QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); - uncompressedPacket.append(uncompressedData); + // these packets are commpressed... + if (VOXEL_PACKETS_COMPRESSED) { + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + QByteArray compressedData((const char*)packetData + numBytesPacketHeader, + messageLength - numBytesPacketHeader); + QByteArray uncompressedData = qUncompress(compressedData); + QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); + uncompressedPacket.append(uncompressedData); - app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); + app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); + } else { + app->_voxels.parseData(packetData, messageLength); + } app->_voxels.setDataSourceUUID(QUuid()); } } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index acbd4b3024..62419565c6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -595,7 +595,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, NULL, getDataSourceUUID()); + ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); unlockTree(); @@ -605,7 +605,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree - ReadBitstreamToTreeParams args(NO_COLOR, NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, NULL, getDataSourceUUID()); + ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); unlockTree(); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 8dce11fb5d..03cd278c52 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -102,38 +102,48 @@ void VoxelNodeData::resetVoxelPacket() { int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - _voxelPacketAvailableBytes = (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - numBytesPacketHeader; - compressPacket(); + + if (VOXEL_PACKETS_COMPRESSED) { + _voxelPacketAvailableBytes = (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - numBytesPacketHeader; + compressPacket(); + } else { + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; + } _voxelPacketWaiting = false; } bool VoxelNodeData::willFit(unsigned char* buffer, int bytes) { - int uncompressedLength = getPacketLengthUncompressed(); - const int MAX_COMPRESSION = 9; - // we only want to compress the data payload, not the message header - int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); + bool wouldFit = false; + if (VOXEL_PACKETS_COMPRESSED) { + int uncompressedLength = getPacketLengthUncompressed(); + const int MAX_COMPRESSION = 9; + // we only want to compress the data payload, not the message header + int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); - // start with the current uncompressed data - QByteArray uncompressedTestData((const char*)_voxelPacket + numBytesPacketHeader, - uncompressedLength - numBytesPacketHeader); + // start with the current uncompressed data + QByteArray uncompressedTestData((const char*)_voxelPacket + numBytesPacketHeader, + uncompressedLength - numBytesPacketHeader); - // append this next buffer... - uncompressedTestData.append((const char*)buffer, bytes); + // append this next buffer... + uncompressedTestData.append((const char*)buffer, bytes); - // test compress it - QByteArray compressedData = qCompress(uncompressedTestData, MAX_COMPRESSION); + // test compress it + QByteArray compressedData = qCompress(uncompressedTestData, MAX_COMPRESSION); - bool wouldFit = (compressedData.size() + numBytesPacketHeader) <= MAX_VOXEL_PACKET_SIZE; + wouldFit = (compressedData.size() + numBytesPacketHeader) <= MAX_VOXEL_PACKET_SIZE; - /* - if (!wouldFit) { - printf("would not fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", - getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + /* + if (!wouldFit) { + printf("would not fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", + getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + } else { + printf("would fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", + getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + } + */ } else { - printf("would fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", - getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); + wouldFit = bytes <= _voxelPacketAvailableBytes; } - */ return wouldFit; } @@ -145,8 +155,25 @@ void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { compressPacket(); } +const unsigned char* VoxelNodeData::getPacket() const { + if (VOXEL_PACKETS_COMPRESSED) { + return (const unsigned char*)_compressedPacket.constData(); + } + return _voxelPacket; +} + +int VoxelNodeData::getPacketLength() const { + if (VOXEL_PACKETS_COMPRESSED) { + return _compressedPacket.size(); + } + return getPacketLengthUncompressed(); +} + int VoxelNodeData::getPacketLengthUncompressed() const { - return (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - _voxelPacketAvailableBytes; + if (VOXEL_PACKETS_COMPRESSED) { + return (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - _voxelPacketAvailableBytes; + } + return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; } void VoxelNodeData::compressPacket() { diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index ad928280d5..92ae5fc6c8 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -31,8 +31,8 @@ public: void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet bool willFit(unsigned char* buffer, int bytes); // tests to see if the bytes will fit - const unsigned char* getPacket() const { return (const unsigned char*)_compressedPacket.constData(); } - int getPacketLength() const { return _compressedPacket.size(); } + const unsigned char* getPacket() const; + int getPacketLength() const; int getPacketLengthUncompressed() const; bool isPacketWaiting() const { return _voxelPacketWaiting; } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 6c3bdd07cc..dbf2942793 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -335,7 +335,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, - NO_EXISTS_BITS /*WANT_EXISTS_BITS*/, DONT_CHOP, wantDelta, lastViewFrustum, + WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index e0cd514214..4fb7775ad0 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -62,4 +62,5 @@ const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs const int DEFAULT_MAX_VOXEL_PPS = 600; // the default maximum PPS we think a voxel server should send to a client +const bool VOXEL_PACKETS_COMPRESSED = false; #endif \ No newline at end of file From e2e9c29824ab79dffb83e21fd3bfab596e626b93 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 13:26:28 -0800 Subject: [PATCH 04/77] implement old vs new side by side encoding to test for correctness --- .../src/VoxelNodeData.cpp | 11 +- .../src/VoxelSendThread.cpp | 6 +- libraries/voxels/src/VoxelPacket.cpp | 21 ++- libraries/voxels/src/VoxelPacket.h | 1 + libraries/voxels/src/VoxelTree.cpp | 143 ++++++++++++++---- libraries/voxels/src/VoxelTree.h | 7 +- 6 files changed, 150 insertions(+), 39 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 03cd278c52..3926435157 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -18,7 +18,6 @@ const int UNCOMPRESSED_SIZE_MULTIPLE = 20; VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelQuery(owningNode), _viewSent(false), - _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE), _maxSearchLevel(1), _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), @@ -31,11 +30,17 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lodChanged(false), _lodInitialized(false) { - _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE]; + if (VOXEL_PACKETS_COMPRESSED) { + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE; + } else { + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; + } + _voxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _voxelPacketAt = _voxelPacket; - _lastVoxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE]; + _lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; + resetVoxelPacket(); } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index dbf2942793..04256af483 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -344,8 +344,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); _tempPacket.reset(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, - nodeData->nodeBag, params); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, + _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, + &_tempPacket, + nodeData->nodeBag, params); nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 109847ffe6..945cb63a4f 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -34,6 +34,17 @@ bool VoxelPacket::append(const unsigned char* data, int length) { return success; } +bool VoxelPacket::append(unsigned char byte) { + bool success = false; + if (_bytesAvailable > 0) { + _buffer[_bytesInUse] = byte; + _bytesInUse++; + _bytesAvailable--; + success = true; + } + return success; +} + bool VoxelPacket::setByte(int offset, unsigned char byte) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { @@ -76,6 +87,8 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) { bool success = false; if (_bytesAvailable > 0) { _buffer[_bytesInUse] = bitmask; + _bytesInUse++; + _bytesAvailable--; success = true; } return success; @@ -84,8 +97,12 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) { bool VoxelPacket::appendColor(rgbColor color) { // eventually we can make this use a dictionary... bool success = false; - if (_bytesAvailable > sizeof(rgbColor)) { - success = append((const unsigned char*)&color, sizeof(rgbColor)); + const int BYTES_PER_COLOR = 3; + if (_bytesAvailable > BYTES_PER_COLOR) { + append(color[0]); + append(color[1]); + append(color[2]); + success = true; } return success; } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 3aac7ac2a2..e37ed49a99 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -30,6 +30,7 @@ public: void endLevel(); bool append(const unsigned char* data, int length); /// appends raw bytes + bool append(unsigned char byte); /// append a single byte bool setByte(int offset, unsigned char byte); /// sets a single raw byte from previously appended portion of the stream int getBytesInUse() const { return _bytesInUse; } int getBytesAvailable() const { return _bytesAvailable; } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8c6f2128a4..c2ea538a01 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1020,9 +1020,13 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& return args.found; } -int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, - EncodeBitstreamParams& params) { +int VoxelTree::encodeTreeBitstream(VoxelNode* node, + unsigned char* outputBuffer, int availableBytes, + VoxelPacket* packet, VoxelNodeBag& bag, + EncodeBitstreamParams& params) { + + unsigned char* originalOutputBuffer = outputBuffer; // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -1046,15 +1050,31 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNo unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); packet->startSubTree(newCode); if (newCode) { + // old way... codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); + memcpy(outputBuffer, newCode, codeLength); + + // do this! + delete newCode; } else { codeLength = 1; + + // old way.... + *outputBuffer = 0; // root } } else { + // new way packet->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); + + // old way + memcpy(outputBuffer, node->getOctalCode(), codeLength); } bytesWritten += codeLength; // keep track of byte count + + // old way... + outputBuffer += codeLength; // move the pointer + availableBytes -= codeLength; // keep track or remaining space int currentEncodeLevel = 0; @@ -1064,7 +1084,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNo params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, packet, bag, params, currentEncodeLevel); + int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, packet, bag, params, currentEncodeLevel); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -1088,10 +1108,25 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNo } doneEncoding(node); + + // debug compare the buffer to the packet... + printf("encodeTreeBitstream()... bytesWritten=%d\n",bytesWritten); + printf(" originalOutputBuffer...\n"); + outputBufferBits(originalOutputBuffer, bytesWritten); + printf(" packet...\n"); + outputBufferBits(packet->getStartOfBuffer(), bytesWritten); + if (memcmp(originalOutputBuffer, packet->getStartOfBuffer(), bytesWritten) == 0) { + printf("... they MATCH ...\n"); + } else { + printf("... they DO NOT MATCH!!!!! ...\n"); + } + return bytesWritten; } -int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, +int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, + unsigned char* outputBuffer, int availableBytes, + VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const { // How many bytes have we written so far at this level; @@ -1234,14 +1269,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet unsigned char childrenExistInPacketBits = 0; unsigned char childrenColoredBits = 0; - //const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); + const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); const int BYTES_PER_COLOR = 3; - //const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); - //const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); + const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; // Make our local buffer large enough to handle writing at this level in case we need to. - //unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; - //unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; + unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; packet->startLevel(); int inViewCount = 0; @@ -1423,8 +1458,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet } } } - //*writeToThisLevelBuffer = childrenColoredBits; - //writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer + + // old way... + *writeToThisLevelBuffer = childrenColoredBits; + writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer bool continueThisLevel = true; continueThisLevel = packet->appendBitMask(childrenColoredBits); @@ -1452,8 +1489,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet break; // no point in continuing } - //memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR); - //writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + // old way... + memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR); + writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color @@ -1469,8 +1507,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits if (continueThisLevel && params.includeExistsBits) { - //*writeToThisLevelBuffer = childrenExistInTreeBits; - //writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer + + // old way... + *writeToThisLevelBuffer = childrenExistInTreeBits; + writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); @@ -1485,22 +1525,30 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet // write the child exist bits if (continueThisLevel) { continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); - //*writeToThisLevelBuffer = childrenExistInPacketBits; - bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count - if (params.stats) { - params.stats->existsInPacketBitsWritten(); + + // old way... + *writeToThisLevelBuffer = childrenExistInPacketBits; + + if (continueThisLevel) { + 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. keepDiggingDeeper = (inViewNotLeafCount > 0); - // If we have enough room to copy our local results into the buffer, then do so... - //int availableBytes = packet->getBytesAvailable(); - //if (availableBytes >= bytesAtThisLevel) { - // packet->append(&thisLevelBuffer[0], bytesAtThisLevel); - //} else { - + // old way... + if (availableBytes >= bytesAtThisLevel) { + memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); + outputBuffer += bytesAtThisLevel; + availableBytes -= bytesAtThisLevel; + } else { + continueThisLevel = false; // ??? + } + // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (!continueThisLevel) { @@ -1527,6 +1575,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet // // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packet->getByteOffset(sizeof(childrenExistInPacketBits)); + unsigned char* childExistsPlaceHolderOLD = outputBuffer-sizeof(childrenExistInPacketBits); // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, @@ -1534,7 +1583,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet // a single recursive pass in distance sorted order, but retain standard order in our encoded packet int recursiveSliceSizes[NUMBER_OF_CHILDREN]; unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; + unsigned char* recursiveSliceStartsOLD[NUMBER_OF_CHILDREN]; unsigned char* firstRecursiveSlice = packet->getEndOfBuffer(); + unsigned char* firstRecursiveSliceOLD = outputBuffer; int allSlicesSize = 0; // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so @@ -1548,9 +1599,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet int thisLevel = currentEncodeLevel; // remember this for reshuffling recursiveSliceStarts[originalIndex] = packet->getEndOfBuffer(); + recursiveSliceStartsOLD[originalIndex] = outputBuffer; - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, - params, thisLevel); + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, + outputBuffer, availableBytes, + packet, bag, + params, thisLevel); // remember this for reshuffling recursiveSliceSizes[originalIndex] = childTreeBytesOut; @@ -1585,12 +1639,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet bytesAtThisLevel += childTreeBytesOut; + //old way + availableBytes -= childTreeBytesOut; + outputBuffer += childTreeBytesOut; + // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask if (childTreeBytesOut == 0) { // remove this child's bit... childrenExistInPacketBits -= (1 << (7 - originalIndex)); + // repair the child exists mask + *childExistsPlaceHolderOLD = childrenExistInPacketBits; packet->setByte(childExistsPlaceHolder, childrenExistInPacketBits); // If this is the last of the child exists bits, then we're actually be rolling out the entire tree @@ -1624,6 +1684,26 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet // now that all slices are back in the correct order, copy them to the correct output buffer memcpy(firstRecursiveSlice, &tempReshuffleBuffer[0], allSlicesSize); + + + // DO IT AGAIN FOR OLD WAY.... + unsigned char* tempBufferToOLD = &tempReshuffleBuffer[0]; // this is our temporary destination + + // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree + // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them + // back into original distance order + for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { + if (oneAtBit(childrenExistInPacketBits, originalIndex)) { + int thisSliceSize = recursiveSliceSizes[originalIndex]; + unsigned char* thisSliceStartsOLD = recursiveSliceStartsOLD[originalIndex]; + + memcpy(tempBufferToOLD, thisSliceStartsOLD, thisSliceSize); + tempBufferToOLD += thisSliceSize; + } + } + + // now that all slices are back in the correct order, copy them to the correct output buffer + memcpy(firstRecursiveSliceOLD, &tempReshuffleBuffer[0], allSlicesSize); } @@ -1833,6 +1913,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { nodeBag.insert(rootNode); } + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; @@ -1841,7 +1922,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); file.write((const char*)packet.getStartOfBuffer(), bytesWritten); } @@ -1868,6 +1949,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); } + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; @@ -1876,7 +1958,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); - bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); @@ -1897,6 +1979,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; @@ -1905,7 +1988,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); // ask destination tree to read the bitstream bool wantImportProgress = true; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index af92fcebcd..a079667af7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -164,7 +164,8 @@ public: void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData=NULL); - int encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, + int encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, + VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } @@ -222,7 +223,9 @@ private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); - int encodeTreeBitstreamRecursion(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, + int encodeTreeBitstreamRecursion(VoxelNode* node, + unsigned char* outputBuffer, int availableBytes, + VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const; static bool countVoxelsOperation(VoxelNode* node, void* extraData); From 9784288b63adcc154646d07d6551b10c5211e81e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 13:51:40 -0800 Subject: [PATCH 05/77] added some debugging --- libraries/voxels/src/VoxelTree.cpp | 23 +++++++++++++---------- voxel-edit/src/main.cpp | 4 ++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c2ea538a01..6df4cc4071 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1110,17 +1110,20 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, doneEncoding(node); // debug compare the buffer to the packet... - printf("encodeTreeBitstream()... bytesWritten=%d\n",bytesWritten); - printf(" originalOutputBuffer...\n"); - outputBufferBits(originalOutputBuffer, bytesWritten); - printf(" packet...\n"); - outputBufferBits(packet->getStartOfBuffer(), bytesWritten); - if (memcmp(originalOutputBuffer, packet->getStartOfBuffer(), bytesWritten) == 0) { - printf("... they MATCH ...\n"); - } else { - printf("... they DO NOT MATCH!!!!! ...\n"); + bool debug = false; + if (debug) { + printf("encodeTreeBitstream()... bytesWritten=%d\n",bytesWritten); + printf(" originalOutputBuffer...\n"); + outputBufferBits(originalOutputBuffer, bytesWritten); + printf(" packet...\n"); + outputBufferBits(packet->getStartOfBuffer(), bytesWritten); + if (memcmp(originalOutputBuffer, packet->getStartOfBuffer(), bytesWritten) == 0) { + printf("... they MATCH ...\n"); + } else { + printf("... they DO NOT MATCH!!!!! ...\n"); + } } - + return bytesWritten; } diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 5f67a46163..e24638389a 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -45,6 +45,7 @@ void voxelTutorial(VoxelTree * tree) { node->getColor()[0], node->getColor()[1], node->getColor()[2]); } + /*** // here's an example of how to delete a voxel printf("attempting to delete corner point 0,0,0\n"); tree->deleteVoxelAt(0, 0, 0, voxelSize); @@ -55,6 +56,7 @@ void voxelTutorial(VoxelTree * tree) { } else { printf("corner point 0,0,0 does not exists...\n"); } + ***/ } @@ -350,7 +352,9 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); + printf("BEFORE writeToSVOFile()\n"); myTree.writeToSVOFile("voxels.svo"); + printf("AFTER writeToSVOFile()\n"); } return 0; From e0c55be4e29a3441258b3369bce5744884050555 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 15:21:29 -0800 Subject: [PATCH 06/77] more debug --- libraries/shared/src/SharedUtil.cpp | 10 ++--- .../src/VoxelSendThread.cpp | 38 +++++++++++-------- libraries/voxels/src/VoxelTree.cpp | 17 +++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 99b24979cc..82153ab887 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -71,18 +71,18 @@ void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - qDebug("[ %d (%c): ", byte, byte); + printf("[ %d (%c): ", byte, byte); } else { - qDebug("[ %d (0x%x): ", byte, byte); + printf("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - qDebug("%d", byte >> (7 - i) & 1); + printf("%d", byte >> (7 - i) & 1); } - qDebug(" ] "); + printf(" ] "); if (withNewLine) { - qDebug("\n"); + printf("\n"); } } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 04256af483..c59c091a7e 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -112,12 +112,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - qDebug("Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); - + if (false) { + qDebug("Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); + } + // actually send it NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); } else { @@ -135,11 +137,13 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + if (false) { + qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); + } } nodeData->stats.markAsSent(); } else { @@ -152,11 +156,13 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + if (false) { + qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + totalPackets, + nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); + } } // remember to track our stats nodeData->stats.packetSent(nodeData->getPacketLength()); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6df4cc4071..aa08241327 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1927,6 +1927,23 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); + + + // debug compare the buffer to the packet... + bool debug = true; + if (debug) { + printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); + printf(" &outputBuffer[0]...\n"); + outputBufferBits(&outputBuffer[0], bytesWritten); + printf(" packet...\n"); + outputBufferBits(packet.getStartOfBuffer(), bytesWritten); + if (memcmp(&outputBuffer[0], packet.getStartOfBuffer(), bytesWritten) == 0) { + printf("... they MATCH ...\n"); + } else { + printf("... they DO NOT MATCH!!!!! ...\n"); + } + } + file.write((const char*)packet.getStartOfBuffer(), bytesWritten); } } From e8c3670cddadd6b13cade3ed4b4c81f8fc77d273 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 20:18:19 -0800 Subject: [PATCH 07/77] added packet.reset() in writeToSVO() --- libraries/voxels/src/VoxelTree.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index aa08241327..5fb7648ddb 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1925,6 +1925,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + packet.reset(); // is there a better way to do this? could we fit more? bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); From 5a9baf27799ebd6729f56cd02e45002bf2168bd2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 20:36:09 -0800 Subject: [PATCH 08/77] moved some debug code --- libraries/voxels/src/VoxelTree.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5fb7648ddb..8b64df0402 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1929,9 +1929,10 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); + printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); // debug compare the buffer to the packet... - bool debug = true; + bool debug = false; if (debug) { printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); printf(" &outputBuffer[0]...\n"); From b9429eeb1e92e0d3c1a2af38340110b4fa673322 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 21:18:31 -0800 Subject: [PATCH 09/77] working version of writeToSVO that uses VoxelPacket and fills it to limit before writing --- libraries/voxels/src/VoxelTree.cpp | 66 +++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8b64df0402..c07dce5015 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1919,35 +1919,73 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; + bool lastPacketWritten = false; while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); + + int packetStartsAt = packet.getBytesInUse(); lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - packet.reset(); // is there a better way to do this? could we fit more? bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); - + + int packetEndsAt = packet.getBytesInUse(); + printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); - // debug compare the buffer to the packet... - bool debug = false; - if (debug) { - printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); - printf(" &outputBuffer[0]...\n"); - outputBufferBits(&outputBuffer[0], bytesWritten); - printf(" packet...\n"); - outputBufferBits(packet.getStartOfBuffer(), bytesWritten); - if (memcmp(&outputBuffer[0], packet.getStartOfBuffer(), bytesWritten) == 0) { - printf("... they MATCH ...\n"); + // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet + // and reinsert the node in our bag and try again... + if (bytesWritten == 0) { + + if (packet.getBytesInUse()) { + printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getBytesInUse()); + file.write((const char*)packet.getStartOfBuffer(), packet.getBytesInUse()); + lastPacketWritten = true; } else { - printf("... they DO NOT MATCH!!!!! ...\n"); + printf("writeToSVOFile()... ODD!!! NOTHING TO WRITE???\n"); + } + + printf("writeToSVOFile()... resetting packet...\n"); + packet.reset(); // is there a better way to do this? could we fit more? + nodeBag.insert(subTree); + + + } else { + printf("writeToSVOFile()... PROCEEDING without resetting packet...\n"); + lastPacketWritten = false; + } + + + // debug compare the buffer to the packet... + bool debug = true; + if (debug) { + if (bytesWritten > 0) { + unsigned char* packetCompare = packet.getStartOfBuffer() + packetStartsAt; + if (memcmp(&outputBuffer[0], packetCompare, bytesWritten) == 0) { + printf("... they MATCH ...\n"); + } else { + printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); + + printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); + printf(" &outputBuffer[0]...\n"); + outputBufferBits(&outputBuffer[0], bytesWritten); + printf(" packet...\n"); + outputBufferBits(packet.getStartOfBuffer(), bytesWritten); + + printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); + } } } - file.write((const char*)packet.getStartOfBuffer(), bytesWritten); } + + if (!lastPacketWritten) { + printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getBytesInUse()); + file.write((const char*)packet.getStartOfBuffer(), packet.getBytesInUse()); + } + } file.close(); } From c25199c80ad439a767ce6dbaacda99b28ea2fcab Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 21:27:37 -0800 Subject: [PATCH 10/77] removed some debugging --- libraries/voxels/src/VoxelTree.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c07dce5015..63f435b101 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1933,33 +1933,23 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { int packetEndsAt = packet.getBytesInUse(); - printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); - // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet // and reinsert the node in our bag and try again... if (bytesWritten == 0) { - if (packet.getBytesInUse()) { printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getBytesInUse()); file.write((const char*)packet.getStartOfBuffer(), packet.getBytesInUse()); lastPacketWritten = true; - } else { - printf("writeToSVOFile()... ODD!!! NOTHING TO WRITE???\n"); } - - printf("writeToSVOFile()... resetting packet...\n"); packet.reset(); // is there a better way to do this? could we fit more? nodeBag.insert(subTree); - - } else { - printf("writeToSVOFile()... PROCEEDING without resetting packet...\n"); lastPacketWritten = false; } // debug compare the buffer to the packet... - bool debug = true; + bool debug = false; if (debug) { if (bytesWritten > 0) { unsigned char* packetCompare = packet.getStartOfBuffer() + packetStartsAt; From 4fc9d5409c9ba14a7d8e78b689e7672553a83713 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 23:46:12 -0800 Subject: [PATCH 11/77] voxel sender now uses maximum bytes in packets with VoxelPacket class --- .../src/VoxelSendThread.cpp | 64 +++++++++++++++---- libraries/voxels/src/VoxelConstants.h | 4 +- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index c59c091a7e..42edd8e4a1 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -85,6 +85,8 @@ int totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { + bool debug = true; + int packetsSent = 0; // Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about @@ -112,7 +114,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - if (false) { + if (debug) { qDebug("Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, @@ -137,7 +139,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - if (false) { + if (debug) { qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, @@ -156,7 +158,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; - if (false) { + if (debug) { qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, @@ -181,6 +183,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod int packetsSentThisInterval = 0; bool somethingToSend = true; // assume we have something + _tempPacket.reset(); // reset at top of distributor // FOR NOW... node tells us if it wants to receive only view frustum deltas bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); @@ -302,6 +305,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); } + + bool lastPacketSent = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { if (_myServer->wantsDebugVoxelSending()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", @@ -323,7 +328,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->nodeBag.count()); } break; - } + } if (!nodeData->nodeBag.isEmpty()) { VoxelNode* subTree = nodeData->nodeBag.extract(); @@ -349,29 +354,62 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - _tempPacket.reset(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, &_tempPacket, nodeData->nodeBag, params); nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); - - // NOTE: could be better, the bytesWritten might be compressable... - if (nodeData->willFit(_tempPacket.getStartOfBuffer(), bytesWritten)) { - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), bytesWritten); - } else { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), bytesWritten); + + // if bytesWritten == 0 it means the subTree couldn't fit... which means we should send the + // packet and reset it. + if (_tempPacket.getBytesInUse() > 0) { + if (bytesWritten == 0) { + if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } else { + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } + lastPacketSent = true; + _tempPacket.reset(); + } else { + lastPacketSent = false; + } } } else { + if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { + if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } else { + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } + lastPacketSent = true; + _tempPacket.reset(); + } if (nodeData->isPacketWaiting()) { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } - //packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left somethingToSend = false; } } + if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { + if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } else { + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); +printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } + lastPacketSent = true; + _tempPacket.reset(); + } // send the environment packet if (shouldSendEnvironments) { diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 4fb7775ad0..0151789c4e 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include // this is where the coordinate system is represented @@ -32,7 +34,7 @@ const float DEFAULT_VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f; const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; -const int MAX_VOXEL_PACKET_SIZE = 1492; +const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; // 6 sides * 4 corners per side From 48dad5ab86734bcb7367d438eb3b2b725b1392dd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 09:49:50 -0800 Subject: [PATCH 12/77] fix bug in packet filling related to octcodes for new trees not fitting --- .../src/VoxelSendThread.cpp | 29 ++++++++- libraries/voxels/src/VoxelPacket.cpp | 16 +++-- libraries/voxels/src/VoxelPacket.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 59 +++++++++++++++++-- 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 42edd8e4a1..f04558d3a0 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -354,17 +354,44 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); + + int packetStartsAt = _tempPacket.getBytesInUse(); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, &_tempPacket, nodeData->nodeBag, params); nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); + + + bool debug = true; + if (debug) { + if (bytesWritten > 0) { + unsigned char* packetCompare = _tempPacket.getStartOfBuffer() + packetStartsAt; + if (memcmp(&_tempOutputBuffer[0], packetCompare, bytesWritten) == 0) { + printf("... they MATCH ...\n"); + } else { + printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); + + printf("deepestLevelVoxelDistributor()... bytesWritten=%d\n",bytesWritten); + printf(" &_tempOutputBuffer[0]...\n"); + outputBufferBits(&_tempOutputBuffer[0], bytesWritten); + printf(" packet...\n"); + outputBufferBits(packetCompare, bytesWritten); + + printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); + } + } + } + + // if bytesWritten == 0 it means the subTree couldn't fit... which means we should send the // packet and reset it. if (_tempPacket.getBytesInUse() > 0) { - if (bytesWritten == 0) { + bool sendNow = (bytesWritten == 0); + if (sendNow) { if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 945cb63a4f..4f37d41c3f 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -56,17 +56,21 @@ bool VoxelPacket::setByte(int offset, unsigned char byte) { -void VoxelPacket::startSubTree(const unsigned char* octcode) { - _subTreeAt = _bytesInUse; +bool VoxelPacket::startSubTree(const unsigned char* octcode) { + bool success = false; + int possibleStartAt = _bytesInUse; if (octcode) { int length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode)); - append(octcode, length); + success = append(octcode, length); } else { // NULL case, means root node, which is 0 - _buffer[_bytesInUse] = 0; - _bytesInUse += 1; - _bytesAvailable -= 1; + unsigned char byte = 0; + success = append(byte); } + if (success) { + _subTreeAt = possibleStartAt; + } + return success; } void VoxelPacket::endSubTree() { diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index e37ed49a99..1f436b4463 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -19,7 +19,7 @@ public: ~VoxelPacket(); void reset(); - void startSubTree(const unsigned char* octcode = NULL); + bool startSubTree(const unsigned char* octcode = NULL); void endSubTree(); void discardSubTree(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 63f435b101..dd1796f0b3 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,6 +286,8 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. if (!oneAtBit(childrenInTreeMask, i) && destinationNode->getChildAtIndex(i)) { +printf("CALLING destinationNode->safeDeepDeleteChildAtIndex(i) because of EXISTS_BITS destinationNode->level=%d childIndex=%d\n", + destinationNode->getLevel(), i); destinationNode->safeDeepDeleteChildAtIndex(i); _isDirty = true; // by definition! } @@ -1045,10 +1047,15 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } // write the octal code + bool roomForOctalCode = false; // assume the worst + if (packet->getBytesInUse() > 0) { + printf("line: %d calling packet->startSubTree()... packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + } int codeLength; if (params.chopLevels) { unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); - packet->startSubTree(newCode); + roomForOctalCode = packet->startSubTree(newCode); + if (newCode) { // old way... codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); @@ -1064,17 +1071,28 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } } else { // new way - packet->startSubTree(node->getOctalCode()); + roomForOctalCode = packet->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); // old way memcpy(outputBuffer, node->getOctalCode(), codeLength); } + + // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... + if (!roomForOctalCode) { + doneEncoding(node); + printf(">>>>>>>>>>>>>>>>>>>>>>>>> line: %d !roomForOctalCode packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + return bytesWritten; + } + bytesWritten += codeLength; // keep track of byte count // old way... outputBuffer += codeLength; // move the pointer availableBytes -= codeLength; // keep track or remaining space + if (packet->getBytesInUse() > 1) { + printf("line: %d called packet->startSubTree()... AFTER packet->getBytesInUse()=%d codeLength=%d\n", __LINE__, packet->getBytesInUse(),codeLength); + } int currentEncodeLevel = 0; @@ -1104,7 +1122,18 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } if (bytesWritten == 0) { + if (packet->getBytesInUse() > 1) { + printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... BEFORE packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); + } packet->discardSubTree(); + if (packet->getBytesInUse() > 0) { + printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... AFTER packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); + } + } else { + packet->endSubTree(); + if (packet->getBytesInUse() > 0) { + printf("line: %d <> calling packet->endSubTree()... AFTER packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + } } doneEncoding(node); @@ -1131,7 +1160,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const { - // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1280,6 +1308,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; + printf("line: %d calling packet->startLevel()... packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->startLevel(); int inViewCount = 0; @@ -1469,6 +1498,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, bool continueThisLevel = true; continueThisLevel = packet->appendBitMask(childrenColoredBits); + if (!continueThisLevel) { + printf("packet->appendBitMask(childrenColoredBits) returned FALSE....\n"); + } + if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count if (params.stats) { @@ -1489,6 +1522,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendColor(color); if (!continueThisLevel) { + printf("packet->appendColor() i=%d returned FALSE....\n", i); break; // no point in continuing } @@ -1507,6 +1541,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } } + if (!continueThisLevel) { + printf("after colores continueThisLevel=FALSE....\n"); + } + // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits if (continueThisLevel && params.includeExistsBits) { @@ -1517,6 +1555,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); + if (!continueThisLevel) { + printf("packet->appendBitMask(childrenExistInTreeBits) returned FALSE....\n"); + } + if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count if (params.stats) { @@ -1528,6 +1570,11 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write the child exist bits if (continueThisLevel) { continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); + + if (!continueThisLevel) { + printf("packet->appendBitMask(childrenExistInPacketBits) returned FALSE....\n"); + } + // old way... *writeToThisLevelBuffer = childrenExistInPacketBits; @@ -1549,13 +1596,16 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; } else { + printf("line: %d setting continueThisLevel = false\n",__LINE__); continueThisLevel = false; // ??? } // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (!continueThisLevel) { + printf("line: %d <> calling packet->discardLevel()... BEFORE packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->discardLevel(); + printf("line: %d <> called packet->discardLevel()... AFTER packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); bag.insert(node); // don't need to check node here, because we can't get here with no node @@ -1563,6 +1613,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, params.stats->didntFit(node); } + printf("line: %d <> returning 0...\n",__LINE__); return 0; } @@ -1931,8 +1982,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); unlock(); - int packetEndsAt = packet.getBytesInUse(); - // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet // and reinsert the node in our bag and try again... if (bytesWritten == 0) { From a426f97e520a151c1315cd7c238d70616171c47d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 10:04:59 -0800 Subject: [PATCH 13/77] removing some debug output --- .../src/VoxelSendThread.cpp | 14 ++++---- libraries/voxels/src/VoxelTree.cpp | 34 ++++++++----------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index f04558d3a0..b97c3a886d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -365,7 +365,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().unlock(); - bool debug = true; + bool debug = false; if (debug) { if (bytesWritten > 0) { unsigned char* packetCompare = _tempPacket.getStartOfBuffer() + packetStartsAt; @@ -393,11 +393,11 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod bool sendNow = (bytesWritten == 0); if (sendNow) { if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } lastPacketSent = true; @@ -409,11 +409,11 @@ printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempP } else { if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } lastPacketSent = true; @@ -427,11 +427,11 @@ printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempP } if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); +//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } lastPacketSent = true; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index dd1796f0b3..b6a1d2afd0 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1049,7 +1049,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // write the octal code bool roomForOctalCode = false; // assume the worst if (packet->getBytesInUse() > 0) { - printf("line: %d calling packet->startSubTree()... packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + //printf("line: %d calling packet->startSubTree()... packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); } int codeLength; if (params.chopLevels) { @@ -1081,7 +1081,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { doneEncoding(node); - printf(">>>>>>>>>>>>>>>>>>>>>>>>> line: %d !roomForOctalCode packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + //printf(">>>>>>>>>>>>>>>>>>>>>>>>> line: %d !roomForOctalCode packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); return bytesWritten; } @@ -1091,7 +1091,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, outputBuffer += codeLength; // move the pointer availableBytes -= codeLength; // keep track or remaining space if (packet->getBytesInUse() > 1) { - printf("line: %d called packet->startSubTree()... AFTER packet->getBytesInUse()=%d codeLength=%d\n", __LINE__, packet->getBytesInUse(),codeLength); + //printf("line: %d called packet->startSubTree()... AFTER packet->getBytesInUse()=%d codeLength=%d\n", __LINE__, packet->getBytesInUse(),codeLength); } int currentEncodeLevel = 0; @@ -1123,16 +1123,16 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, if (bytesWritten == 0) { if (packet->getBytesInUse() > 1) { - printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... BEFORE packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); + //printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... BEFORE packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); } packet->discardSubTree(); if (packet->getBytesInUse() > 0) { - printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... AFTER packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); + //printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... AFTER packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); } } else { packet->endSubTree(); if (packet->getBytesInUse() > 0) { - printf("line: %d <> calling packet->endSubTree()... AFTER packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); + //printf("line: %d <> calling packet->endSubTree()... AFTER packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); } } @@ -1308,7 +1308,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; - printf("line: %d calling packet->startLevel()... packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); + //printf("line: %d calling packet->startLevel()... packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->startLevel(); int inViewCount = 0; @@ -1499,7 +1499,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendBitMask(childrenColoredBits); if (!continueThisLevel) { - printf("packet->appendBitMask(childrenColoredBits) returned FALSE....\n"); + //printf("packet->appendBitMask(childrenColoredBits) returned FALSE....\n"); } if (continueThisLevel) { @@ -1522,7 +1522,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendColor(color); if (!continueThisLevel) { - printf("packet->appendColor() i=%d returned FALSE....\n", i); + //printf("packet->appendColor() i=%d returned FALSE....\n", i); break; // no point in continuing } @@ -1541,10 +1541,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } } - if (!continueThisLevel) { - printf("after colores continueThisLevel=FALSE....\n"); - } - // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits if (continueThisLevel && params.includeExistsBits) { @@ -1556,7 +1552,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); if (!continueThisLevel) { - printf("packet->appendBitMask(childrenExistInTreeBits) returned FALSE....\n"); + //printf("packet->appendBitMask(childrenExistInTreeBits) returned FALSE....\n"); } if (continueThisLevel) { @@ -1572,7 +1568,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); if (!continueThisLevel) { - printf("packet->appendBitMask(childrenExistInPacketBits) returned FALSE....\n"); + //printf("packet->appendBitMask(childrenExistInPacketBits) returned FALSE....\n"); } @@ -1596,16 +1592,16 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; } else { - printf("line: %d setting continueThisLevel = false\n",__LINE__); + //printf("line: %d setting continueThisLevel = false\n",__LINE__); continueThisLevel = false; // ??? } // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (!continueThisLevel) { - printf("line: %d <> calling packet->discardLevel()... BEFORE packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); + //printf("line: %d <> calling packet->discardLevel()... BEFORE packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->discardLevel(); - printf("line: %d <> called packet->discardLevel()... AFTER packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); + //printf("line: %d <> called packet->discardLevel()... AFTER packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); bag.insert(node); // don't need to check node here, because we can't get here with no node @@ -1613,7 +1609,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, params.stats->didntFit(node); } - printf("line: %d <> returning 0...\n",__LINE__); + //printf("line: %d <> returning 0...\n",__LINE__); return 0; } From e60c48208674fa44745f4b6c2c8d6a8e1bb03878 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 12:59:52 -0800 Subject: [PATCH 14/77] supress empty packets in handlePacketSend(), DRY up code in deepestLevelVoxelDistributor() --- .../src/VoxelSendThread.cpp | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index b97c3a886d..34d6bd24c8 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -84,9 +84,9 @@ int totalWastedBytes = 0; int totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = true; + bool packetSent = false; // did we send a packet? int packetsSent = 0; // Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about @@ -115,7 +115,8 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { - qDebug("Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + qDebug("line: %d - Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + __LINE__, totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, @@ -124,9 +125,25 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // actually send it NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + packetSent = true; } else { // not enough room in the packet, send two packets NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + + int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; + ::totalWastedBytes += thisWastedBytes; + ::totalUncompressed += statsMessageLength; + ::totalCompressed += statsMessageLength; + ::totalPackets++; + if (debug) { + qDebug("line: %d - Sending separate stats packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + __LINE__, + totalPackets, + statsMessageLength, ::totalUncompressed, + statsMessageLength, ::totalCompressed, + thisWastedBytes, ::totalWastedBytes); + } + trueBytesSent += statsMessageLength; truePacketsSent++; packetsSent++; @@ -134,13 +151,16 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), nodeData->getPacket(), nodeData->getPacketLength()); - int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + packetSent = true; + + thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); ::totalWastedBytes += thisWastedBytes; ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { - qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + __LINE__, totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, @@ -149,9 +169,12 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& } nodeData->stats.markAsSent(); } else { - // just send the voxel packet - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); + // If there's actually a packet waiting, then send it. + if (nodeData->isPacketWaiting()) { + // just send the voxel packet + NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), + nodeData->getPacket(), nodeData->getPacketLength()); + packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); ::totalWastedBytes += thisWastedBytes; @@ -159,19 +182,24 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { - qDebug("Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", + __LINE__, totalPackets, nodeData->getPacketLengthUncompressed(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, thisWastedBytes, ::totalWastedBytes); } + } } // remember to track our stats - nodeData->stats.packetSent(nodeData->getPacketLength()); - trueBytesSent += nodeData->getPacketLength(); - truePacketsSent++; - packetsSent++; - nodeData->resetVoxelPacket(); + if (packetSent) { + nodeData->stats.packetSent(nodeData->getPacketLength()); + trueBytesSent += nodeData->getPacketLength(); + truePacketsSent++; + packetsSent++; + nodeData->resetVoxelPacket(); + } + return packetsSent; } @@ -306,7 +334,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); } - bool lastPacketSent = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { if (_myServer->wantsDebugVoxelSending()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", @@ -384,58 +411,27 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } } } - - - - // if bytesWritten == 0 it means the subTree couldn't fit... which means we should send the - // packet and reset it. - if (_tempPacket.getBytesInUse() > 0) { - bool sendNow = (bytesWritten == 0); - if (sendNow) { - if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } else { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } - lastPacketSent = true; - _tempPacket.reset(); - } else { - lastPacketSent = false; - } - } } else { - if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { - if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } else { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } - lastPacketSent = true; - _tempPacket.reset(); - } - if (nodeData->isPacketWaiting()) { + // If the bag was empty then we didn't even attempt to encode, and so we know the bytesWritten were 0 + bytesWritten = 0; + somethingToSend = false; // this will cause us to drop out of the loop... + } + + // We only consider sending anything if there is something in the _tempPacket to send... But + // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases + // mean we should send the previous packet contents and reset it. + if (_tempPacket.getBytesInUse() > 0 && bytesWritten == 0) { + if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); + } else { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); } - somethingToSend = false; + _tempPacket.reset(); } } - if (!lastPacketSent && _tempPacket.getBytesInUse() > 0) { - if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } else { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); -//printf("calling writeToPacket() _tempPacket.getBytesInUse()=%d line:%d\n",_tempPacket.getBytesInUse(),__LINE__); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } - lastPacketSent = true; - _tempPacket.reset(); + if (nodeData->isPacketWaiting()) { + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } // send the environment packet From 80cfba465c153612f32b7ca39219298a35ca1ce3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 17:00:39 -0800 Subject: [PATCH 15/77] move sending of packet to immediately following scene end to get better synch of stats packets, also fix duplicate suppression bug --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 4 ++-- libraries/voxel-server-library/src/VoxelSendThread.cpp | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 3926435157..1d42173e7d 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -73,12 +73,12 @@ bool VoxelNodeData::shouldSuppressDuplicatePacket() { // How long has it been since we've sent one, if we're still under our max time, then keep considering // this packet for suppression uint64_t now = usecTimestampNow(); - long sinceFirstSuppressedPacket = now - _firstSuppressedPacket; + int sinceFirstSuppressedPacket = now - _firstSuppressedPacket; const long MAX_TIME_BETWEEN_DUPLICATE_PACKETS = 1000 * 1000; // 1 second. if (sinceFirstSuppressedPacket < MAX_TIME_BETWEEN_DUPLICATE_PACKETS) { // Finally, if we know we've sent at least one duplicate out, then suppress the rest... - if (_duplicatePacketCount > 1) { + if (_duplicatePacketCount >= 1) { shouldSuppress = true; } } else { diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 34d6bd24c8..b76b7edcd4 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -290,8 +290,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t now = usecTimestampNow(); nodeData->setLastTimeBagEmpty(now); } - nodeData->stats.sceneCompleted(); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); if (_myServer->wantDisplayVoxelStats()) { nodeData->stats.printDebugDetails(); @@ -305,6 +305,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (isFullScene) { nodeData->nodeBag.deleteAll(); } + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); // This is the start of "resending" the scene. @@ -430,9 +431,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _tempPacket.reset(); } } - if (nodeData->isPacketWaiting()) { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - } // send the environment packet if (shouldSendEnvironments) { From 01488ed332c7983cdd8936a583058eb16e578333 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 17:23:12 -0800 Subject: [PATCH 16/77] don't send any voxel stats till we've succesfully encoded at least one voxel --- .../voxel-server-library/src/VoxelSendThread.cpp | 14 ++++++++++---- .../voxel-server-library/src/VoxelSendThread.h | 1 + libraries/voxels/src/VoxelSceneStats.h | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index b76b7edcd4..0b0e3c35c0 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -20,7 +20,8 @@ extern EnvironmentData environmentData[3]; VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : _nodeUUID(nodeUUID), - _myServer(myServer) { + _myServer(myServer), + _encodedSomething(false) { } bool VoxelSendThread::process() { @@ -109,7 +110,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); statsMessageLength += nodeData->getPacketLength(); - int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data ::totalWastedBytes += thisWastedBytes; ::totalUncompressed += nodeData->getPacketLengthUncompressed(); ::totalCompressed += nodeData->getPacketLength(); @@ -290,8 +291,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t now = usecTimestampNow(); nodeData->setLastTimeBagEmpty(now); } - nodeData->stats.sceneCompleted(); - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + if (_encodedSomething) { + nodeData->stats.sceneCompleted(); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + } if (_myServer->wantDisplayVoxelStats()) { nodeData->stats.printDebugDetails(); @@ -389,6 +392,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, &_tempPacket, nodeData->nodeBag, params); + if (bytesWritten > 0) { + _encodedSomething = true; + } nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 7283a570a1..304001845a 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -35,6 +35,7 @@ private: unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; VoxelPacket _tempPacket; + bool _encodedSomething; }; #endif // __voxel_server__VoxelSendThread__ diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index 245fe430dd..e273c57174 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -32,6 +32,7 @@ public: /// Call when beginning the computation of a scene. Initializes internal structures void sceneStarted(bool fullScene, bool moving, VoxelNode* root, JurisdictionMap* jurisdictionMap); + bool getIsSceneStarted() const { return _isStarted; } /// Call when the computation of a scene is completed. Finalizes internal structures void sceneCompleted(); @@ -155,7 +156,7 @@ private: int _statsMessageLength; // scene timing data in usecs - bool _isStarted; + bool _isStarted; uint64_t _start; uint64_t _end; uint64_t _elapsed; From 69eee541db5c9b790635e0d9a054d85121b19ea0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 17:53:25 -0800 Subject: [PATCH 17/77] removed some old debug, standardize callers of VoxelPacket to use semantic entry points instead of direct access to bytes --- .../src/VoxelSendThread.cpp | 12 +++---- libraries/voxels/src/VoxelPacket.h | 16 ++++++++-- libraries/voxels/src/VoxelTree.cpp | 31 ++++--------------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 0b0e3c35c0..bf46d4ec4c 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -386,7 +386,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - int packetStartsAt = _tempPacket.getBytesInUse(); + int packetStartsAt = _tempPacket.getNextByteUncompressed(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, @@ -427,13 +427,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // We only consider sending anything if there is something in the _tempPacket to send... But // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. - if (_tempPacket.getBytesInUse() > 0 && bytesWritten == 0) { - if (nodeData->willFit(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse())) { - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } else { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - nodeData->writeToPacket(_tempPacket.getStartOfBuffer(), _tempPacket.getBytesInUse()); - } + if (_tempPacket.hasContent() && bytesWritten == 0) { + nodeData->writeToPacket(_tempPacket.getCompressedData(), _tempPacket.getCompressedSize()); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); } } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 1f436b4463..65c54d83f5 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -32,8 +32,18 @@ public: bool append(const unsigned char* data, int length); /// appends raw bytes bool append(unsigned char byte); /// append a single byte bool setByte(int offset, unsigned char byte); /// sets a single raw byte from previously appended portion of the stream - int getBytesInUse() const { return _bytesInUse; } - int getBytesAvailable() const { return _bytesAvailable; } + + //int getBytesInUse() const { return _bytesInUse; } + //int getBytesAvailable() const { return _bytesAvailable; } + + unsigned char* getCompressedData() { return &_buffer[0]; } /// get pointer to start of compressed stream + int getCompressedSize() const { return _bytesInUse; } /// the size of the packet in compressed form + + /// returns the offset of the next uncompressed byte to be written + int getNextByteUncompressed() const { return _bytesInUse; } + + /// has some content been written to the packet + bool hasContent() const { return (_bytesInUse > 0); } /// returns a byte offset from beginning of stream based on offset from end. /// Positive offsetFromEnd returns that many bytes before the end @@ -41,7 +51,7 @@ public: return _bytesInUse - offsetFromEnd; } - unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to current end of stream buffer + unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to the start of stream buffer unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b6a1d2afd0..e2da5d966c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1048,9 +1048,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // write the octal code bool roomForOctalCode = false; // assume the worst - if (packet->getBytesInUse() > 0) { - //printf("line: %d calling packet->startSubTree()... packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); - } int codeLength; if (params.chopLevels) { unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); @@ -1081,7 +1078,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { doneEncoding(node); - //printf(">>>>>>>>>>>>>>>>>>>>>>>>> line: %d !roomForOctalCode packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); return bytesWritten; } @@ -1090,9 +1086,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // old way... outputBuffer += codeLength; // move the pointer availableBytes -= codeLength; // keep track or remaining space - if (packet->getBytesInUse() > 1) { - //printf("line: %d called packet->startSubTree()... AFTER packet->getBytesInUse()=%d codeLength=%d\n", __LINE__, packet->getBytesInUse(),codeLength); - } int currentEncodeLevel = 0; @@ -1122,18 +1115,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } if (bytesWritten == 0) { - if (packet->getBytesInUse() > 1) { - //printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... BEFORE packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); - } packet->discardSubTree(); - if (packet->getBytesInUse() > 0) { - //printf(">>>>>>>>>>>>>>>>>>> line: %d <> calling packet->discardSubTree()... AFTER packet->getBytesInUse()=%d <<<<<<<<<<<<<\n", __LINE__, packet->getBytesInUse()); - } } else { packet->endSubTree(); - if (packet->getBytesInUse() > 0) { - //printf("line: %d <> calling packet->endSubTree()... AFTER packet->getBytesInUse()=%d\n", __LINE__, packet->getBytesInUse()); - } } doneEncoding(node); @@ -1308,7 +1292,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; - //printf("line: %d calling packet->startLevel()... packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->startLevel(); int inViewCount = 0; @@ -1599,9 +1582,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (!continueThisLevel) { - //printf("line: %d <> calling packet->discardLevel()... BEFORE packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); packet->discardLevel(); - //printf("line: %d <> called packet->discardLevel()... AFTER packet->getBytesInUse()=%d\n",__LINE__,packet->getBytesInUse()); bag.insert(node); // don't need to check node here, because we can't get here with no node @@ -1971,7 +1952,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - int packetStartsAt = packet.getBytesInUse(); + int packetStartsAt = packet.getNextByteUncompressed(); lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); @@ -1981,9 +1962,9 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet // and reinsert the node in our bag and try again... if (bytesWritten == 0) { - if (packet.getBytesInUse()) { - printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getBytesInUse()); - file.write((const char*)packet.getStartOfBuffer(), packet.getBytesInUse()); + if (packet.hasContent()) { + printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getCompressedSize()); + file.write((const char*)packet.getCompressedData(), packet.getCompressedSize()); lastPacketWritten = true; } packet.reset(); // is there a better way to do this? could we fit more? @@ -2017,8 +1998,8 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { } if (!lastPacketWritten) { - printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getBytesInUse()); - file.write((const char*)packet.getStartOfBuffer(), packet.getBytesInUse()); + printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getCompressedSize()); + file.write((const char*)packet.getCompressedData(), packet.getCompressedSize()); } } From 9d8f0b82df0a99856278bdfd77783ca92ddae330 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 17:59:47 -0800 Subject: [PATCH 18/77] make append() private --- libraries/voxels/src/VoxelPacket.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 65c54d83f5..04e52c17ea 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -29,12 +29,9 @@ public: void discardLevel(); void endLevel(); - bool append(const unsigned char* data, int length); /// appends raw bytes - bool append(unsigned char byte); /// append a single byte - bool setByte(int offset, unsigned char byte); /// sets a single raw byte from previously appended portion of the stream - - //int getBytesInUse() const { return _bytesInUse; } - //int getBytesAvailable() const { return _bytesAvailable; } + /// sets a single raw byte from previously appended portion of the uncompressed stream, might fail if the new byte would + /// cause packet to be less compressed, or if offset was out of range. + bool setByte(int offset, unsigned char byte); unsigned char* getCompressedData() { return &_buffer[0]; } /// get pointer to start of compressed stream int getCompressedSize() const { return _bytesInUse; } /// the size of the packet in compressed form @@ -54,8 +51,13 @@ public: unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to the start of stream buffer unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer - private: + /// appends raw bytes, might fail if byte would cause packet to be too large + bool append(const unsigned char* data, int length); + + /// append a single byte, might fail if byte would cause packet to be too large + bool append(unsigned char byte); + unsigned char _buffer[MAX_VOXEL_PACKET_SIZE]; int _bytesInUse; int _bytesAvailable; From 0cd0012aab9c1fc0ac1aec5209bbcafb3cd7cbbb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 20:08:58 -0800 Subject: [PATCH 19/77] cleaning up semantics of VoxelPacket --- .../src/VoxelSendThread.cpp | 4 +- libraries/voxels/src/VoxelPacket.cpp | 31 +++++------ libraries/voxels/src/VoxelPacket.h | 54 ++++++++++++------- libraries/voxels/src/VoxelTree.cpp | 18 +++---- 4 files changed, 63 insertions(+), 44 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index bf46d4ec4c..23f1e53748 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -386,7 +386,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - int packetStartsAt = _tempPacket.getNextByteUncompressed(); + int packetStartsAt = _tempPacket.getUncompressedByteOffset(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, @@ -428,7 +428,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. if (_tempPacket.hasContent() && bytesWritten == 0) { - nodeData->writeToPacket(_tempPacket.getCompressedData(), _tempPacket.getCompressedSize()); + nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); } diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 4f37d41c3f..87d0c90728 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -45,17 +45,15 @@ bool VoxelPacket::append(unsigned char byte) { return success; } -bool VoxelPacket::setByte(int offset, unsigned char byte) { +bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { - _buffer[offset] = byte; + _buffer[offset] = bitmask; success = true; } return success; } - - bool VoxelPacket::startSubTree(const unsigned char* octcode) { bool success = false; int possibleStartAt = _bytesInUse; @@ -83,10 +81,22 @@ void VoxelPacket::discardSubTree() { _bytesAvailable += bytesInSubTree; } -void VoxelPacket::startLevel() { - _levelAt = _bytesInUse; +int VoxelPacket::startLevel() { + int key = _bytesInUse; + return key; } +void VoxelPacket::discardLevel(int key) { + int bytesInLevel = _bytesInUse - key; + _bytesInUse -= bytesInLevel; + _bytesAvailable += bytesInLevel; +} + +void VoxelPacket::endLevel() { + // nothing to do +} + + bool VoxelPacket::appendBitMask(unsigned char bitmask) { bool success = false; if (_bytesAvailable > 0) { @@ -111,12 +121,3 @@ bool VoxelPacket::appendColor(rgbColor color) { return success; } -void VoxelPacket::endLevel() { - _levelAt = _bytesInUse; -} - -void VoxelPacket::discardLevel() { - int bytesInLevel = _bytesInUse - _levelAt; - _bytesInUse -= bytesInLevel; - _bytesAvailable += bytesInLevel; -} diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 04e52c17ea..5a69dabdeb 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -23,31 +23,49 @@ public: void endSubTree(); void discardSubTree(); - void startLevel(); - bool appendBitMask(unsigned char bitmask); - bool appendColor(rgbColor color); - void discardLevel(); - void endLevel(); + /// starts a level marker. returns an opaque key which can be used to discard the level + int startLevel(); + + /// discards all content back to a previous marker key + void discardLevel(int key); - /// sets a single raw byte from previously appended portion of the uncompressed stream, might fail if the new byte would - /// cause packet to be less compressed, or if offset was out of range. - bool setByte(int offset, unsigned char byte); + /// ends a level without discarding it + void endLevel(); - unsigned char* getCompressedData() { return &_buffer[0]; } /// get pointer to start of compressed stream - int getCompressedSize() const { return _bytesInUse; } /// the size of the packet in compressed form + bool appendBitMask(unsigned char bitmask); - /// returns the offset of the next uncompressed byte to be written - int getNextByteUncompressed() const { return _bytesInUse; } + /// updates the value of a bitmask from a previously appended portion of the uncompressed stream, might fail if the new + /// bitmask would cause packet to be less compressed, or if offset was out of range. + bool updatePriorBitMask(int offset, unsigned char bitmask); + + bool appendColor(rgbColor color); + + /// returns a byte offset from beginning of the uncompressed stream based on offset from end. + /// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream + int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } + + /// get access to the finalized data (it may be compressed or rewritten into optimal form) + unsigned char* getFinalizedData() { return &_buffer[0]; } /// get pointer to start of finalized stream + + /// get size of the finalized data (it may be compressed or rewritten into optimal form) + int getFinalizedSize() const { return _bytesInUse; } /// the size of the packet in compressed form + + + //////////////////////////////////// + // XXXBHG: Questions... + // Slice Reshuffle... + // + // 1) getEndOfBuffer() is used by recursive slice shuffling... is there a safer API for that? This usage would probably + // break badly with compression... Especially since we do a memcpy into the uncompressed buffer, we'd need to + // add an "updateBytes()" method... which could definitely fail on compression.... It would also break any RLE we + // might implement, since the order of the colors would clearly change. + // + // 2) add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. + /// has some content been written to the packet bool hasContent() const { return (_bytesInUse > 0); } - /// returns a byte offset from beginning of stream based on offset from end. - /// Positive offsetFromEnd returns that many bytes before the end - int getByteOffset(int offsetFromEnd) const { - return _bytesInUse - offsetFromEnd; - } - unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to the start of stream buffer unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index e2da5d966c..05cb96d81f 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1292,7 +1292,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; - packet->startLevel(); + int thisLevelKey = packet->startLevel(); int inViewCount = 0; int inViewNotLeafCount = 0; @@ -1582,7 +1582,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (!continueThisLevel) { - packet->discardLevel(); + packet->discardLevel(thisLevelKey); bag.insert(node); // don't need to check node here, because we can't get here with no node @@ -1605,7 +1605,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write something, we keep them in the bits, if they don't, we take them out. // // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! - int childExistsPlaceHolder = packet->getByteOffset(sizeof(childrenExistInPacketBits)); + int childExistsPlaceHolder = packet->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); unsigned char* childExistsPlaceHolderOLD = outputBuffer-sizeof(childrenExistInPacketBits); // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the @@ -1682,7 +1682,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // repair the child exists mask *childExistsPlaceHolderOLD = childrenExistInPacketBits; - packet->setByte(childExistsPlaceHolder, childrenExistInPacketBits); + packet->updatePriorBitMask(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) { @@ -1952,7 +1952,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - int packetStartsAt = packet.getNextByteUncompressed(); + int packetStartsAt = packet.getUncompressedByteOffset(); lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); @@ -1963,8 +1963,8 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { // and reinsert the node in our bag and try again... if (bytesWritten == 0) { if (packet.hasContent()) { - printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getCompressedSize()); - file.write((const char*)packet.getCompressedData(), packet.getCompressedSize()); + printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getFinalizedSize()); + file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); lastPacketWritten = true; } packet.reset(); // is there a better way to do this? could we fit more? @@ -1998,8 +1998,8 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { } if (!lastPacketWritten) { - printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getCompressedSize()); - file.write((const char*)packet.getCompressedData(), packet.getCompressedSize()); + printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getFinalizedSize()); + file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); } } From 1d8839947691515e6fe383a04aaee0c3e18a0371 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 22 Nov 2013 20:39:11 -0800 Subject: [PATCH 20/77] cleaning up semantics of VoxelPacket --- .../src/VoxelSendThread.cpp | 23 --------- libraries/voxels/src/VoxelPacket.h | 20 ++++---- libraries/voxels/src/VoxelTree.cpp | 50 +++---------------- 3 files changed, 16 insertions(+), 77 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 23f1e53748..b7ee90e94f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -386,8 +386,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - int packetStartsAt = _tempPacket.getUncompressedByteOffset(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, &_tempPacket, @@ -397,27 +395,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); - - - bool debug = false; - if (debug) { - if (bytesWritten > 0) { - unsigned char* packetCompare = _tempPacket.getStartOfBuffer() + packetStartsAt; - if (memcmp(&_tempOutputBuffer[0], packetCompare, bytesWritten) == 0) { - printf("... they MATCH ...\n"); - } else { - printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); - - printf("deepestLevelVoxelDistributor()... bytesWritten=%d\n",bytesWritten); - printf(" &_tempOutputBuffer[0]...\n"); - outputBufferBits(&_tempOutputBuffer[0], bytesWritten); - printf(" packet...\n"); - outputBufferBits(packetCompare, bytesWritten); - - printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); - } - } - } } else { // If the bag was empty then we didn't even attempt to encode, and so we know the bytesWritten were 0 bytesWritten = 0; diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 5a69dabdeb..d7b27e11c2 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -45,11 +45,17 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - unsigned char* getFinalizedData() { return &_buffer[0]; } /// get pointer to start of finalized stream - + unsigned char* getFinalizedData() { return &_buffer[0]; } /// get size of the finalized data (it may be compressed or rewritten into optimal form) - int getFinalizedSize() const { return _bytesInUse; } /// the size of the packet in compressed form - + int getFinalizedSize() const { return _bytesInUse; } + + /// get pointer to the start of uncompressed stream buffer + unsigned char* getUncompressedData() { return &_buffer[0]; } + /// the size of the packet in uncompressed form + int getUncompressedSize() { return _bytesInUse; } + + /// has some content been written to the packet + bool hasContent() const { return (_bytesInUse > 0); } //////////////////////////////////// // XXXBHG: Questions... @@ -61,12 +67,6 @@ public: // might implement, since the order of the colors would clearly change. // // 2) add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. - - - /// has some content been written to the packet - bool hasContent() const { return (_bytesInUse > 0); } - - unsigned char* getStartOfBuffer() { return &_buffer[0]; } /// get pointer to the start of stream buffer unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer private: diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 05cb96d81f..8c4df7b98a 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1027,8 +1027,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) { - - unsigned char* originalOutputBuffer = outputBuffer; // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -1122,21 +1120,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, doneEncoding(node); - // debug compare the buffer to the packet... - bool debug = false; - if (debug) { - printf("encodeTreeBitstream()... bytesWritten=%d\n",bytesWritten); - printf(" originalOutputBuffer...\n"); - outputBufferBits(originalOutputBuffer, bytesWritten); - printf(" packet...\n"); - outputBufferBits(packet->getStartOfBuffer(), bytesWritten); - if (memcmp(originalOutputBuffer, packet->getStartOfBuffer(), bytesWritten) == 0) { - printf("... they MATCH ...\n"); - } else { - printf("... they DO NOT MATCH!!!!! ...\n"); - } - } - return bytesWritten; } @@ -1952,8 +1935,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - int packetStartsAt = packet.getUncompressedByteOffset(); - lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); @@ -1972,29 +1953,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { } else { lastPacketWritten = false; } - - - // debug compare the buffer to the packet... - bool debug = false; - if (debug) { - if (bytesWritten > 0) { - unsigned char* packetCompare = packet.getStartOfBuffer() + packetStartsAt; - if (memcmp(&outputBuffer[0], packetCompare, bytesWritten) == 0) { - printf("... they MATCH ...\n"); - } else { - printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); - - printf("writeToSVOFile()... bytesWritten=%d\n",bytesWritten); - printf(" &outputBuffer[0]...\n"); - outputBufferBits(&outputBuffer[0], bytesWritten); - printf(" packet...\n"); - outputBufferBits(packet.getStartOfBuffer(), bytesWritten); - - printf("... >>>>>>>>>>>> they DO NOT MATCH!!!!! <<<<<<<<<<<<<<< ...\n"); - } - } - } - } if (!lastPacketWritten) { @@ -2031,6 +1989,8 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); + + packet.reset(); // reset the packet between usage // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); @@ -2038,7 +1998,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); - destinationTree->readBitstreamToTree(packet.getStartOfBuffer(), bytesWritten, args); + destinationTree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); } VoxelNode* destinationStartNode; @@ -2061,6 +2021,8 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); + + packet.reset(); // reset between usage // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); @@ -2069,7 +2031,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // ask destination tree to read the bitstream bool wantImportProgress = true; ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress); - readBitstreamToTree(packet.getStartOfBuffer(), bytesWritten, args); + readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); } } From b1adf82d4bfc7ead57f86f24d2b7a961c912b7db Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:05:37 -0800 Subject: [PATCH 21/77] cleaned up const semantics in streaming voxel packets, fixed double reset bug --- .../src/VoxelSendThread.cpp | 5 +- libraries/voxels/src/VoxelPacket.cpp | 12 ++- libraries/voxels/src/VoxelPacket.h | 20 ++-- libraries/voxels/src/VoxelTree.cpp | 100 +++++++++--------- libraries/voxels/src/VoxelTree.h | 25 ++--- 5 files changed, 82 insertions(+), 80 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index b7ee90e94f..7b95b2291e 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -212,8 +212,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod int packetsSentThisInterval = 0; bool somethingToSend = true; // assume we have something - _tempPacket.reset(); // reset at top of distributor - // FOR NOW... node tells us if it wants to receive only view frustum deltas bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); @@ -404,7 +402,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // We only consider sending anything if there is something in the _tempPacket to send... But // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. - if (_tempPacket.hasContent() && bytesWritten == 0) { + bool sendNow = (bytesWritten == 0); + if (_tempPacket.hasContent() && sendNow) { nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 87d0c90728..e11ce46f51 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -16,7 +16,6 @@ void VoxelPacket::reset() { _bytesInUse = 0; _bytesAvailable = MAX_VOXEL_PACKET_SIZE; _subTreeAt = 0; - _levelAt = 0; } VoxelPacket::~VoxelPacket() { @@ -54,6 +53,15 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { return success; } +bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) { + bool success = false; + if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { + memcpy(&_buffer[offset], replacementBytes, length); + success = true; + } + return success; +} + bool VoxelPacket::startSubTree(const unsigned char* octcode) { bool success = false; int possibleStartAt = _bytesInUse; @@ -79,6 +87,7 @@ void VoxelPacket::discardSubTree() { int bytesInSubTree = _bytesInUse - _subTreeAt; _bytesInUse -= bytesInSubTree; _bytesAvailable += bytesInSubTree; + _subTreeAt = _bytesInUse; // should be the same actually... } int VoxelPacket::startLevel() { @@ -96,7 +105,6 @@ void VoxelPacket::endLevel() { // nothing to do } - bool VoxelPacket::appendBitMask(unsigned char bitmask) { bool success = false; if (_bytesAvailable > 0) { diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index d7b27e11c2..38a1ef3568 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -38,6 +38,10 @@ public: /// bitmask would cause packet to be less compressed, or if offset was out of range. bool updatePriorBitMask(int offset, unsigned char bitmask); + /// updates the uncompressed content of the stream starting at byte offset with replacementBytes for length. + /// Might fail if the new bytes would cause packet to be less compressed, or if offset and length was out of range. + bool updatePriorBytes(int offset, const unsigned char* replacementBytes, int length); + bool appendColor(rgbColor color); /// returns a byte offset from beginning of the uncompressed stream based on offset from end. @@ -50,24 +54,15 @@ public: int getFinalizedSize() const { return _bytesInUse; } /// get pointer to the start of uncompressed stream buffer - unsigned char* getUncompressedData() { return &_buffer[0]; } + const unsigned char* getUncompressedData() { return &_buffer[0]; } /// the size of the packet in uncompressed form int getUncompressedSize() { return _bytesInUse; } /// has some content been written to the packet bool hasContent() const { return (_bytesInUse > 0); } - //////////////////////////////////// - // XXXBHG: Questions... - // Slice Reshuffle... - // - // 1) getEndOfBuffer() is used by recursive slice shuffling... is there a safer API for that? This usage would probably - // break badly with compression... Especially since we do a memcpy into the uncompressed buffer, we'd need to - // add an "updateBytes()" method... which could definitely fail on compression.... It would also break any RLE we - // might implement, since the order of the colors would clearly change. - // - // 2) add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. - unsigned char* getEndOfBuffer() { return &_buffer[_bytesInUse]; } /// get pointer to current end of stream buffer + // XXXBHG: TO DO... + // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. private: /// appends raw bytes, might fail if byte would cause packet to be too large @@ -80,7 +75,6 @@ private: int _bytesInUse; int _bytesAvailable; int _subTreeAt; - int _levelAt; }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8c4df7b98a..2064d3b47f 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -170,7 +170,7 @@ VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode, } // returns the node created! -VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char* codeToReach) { +VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, const unsigned char* codeToReach) { int indexOfNewChild = branchIndexWithDescendant(lastParentNode->getOctalCode(), codeToReach); // If this parent node is a leaf, then you know the child path doesn't exist, so deal with // breaking up the leaf first, which will also create a child path @@ -193,7 +193,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } } -int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead, +int VoxelTree::readNodeData(VoxelNode* destinationNode, const unsigned char* nodeData, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { // give this destination node the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; @@ -296,10 +296,10 @@ printf("CALLING destinationNode->safeDeepDeleteChildAtIndex(i) because of EXISTS return bytesRead; } -void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, +void VoxelTree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args) { int bytesRead = 0; - unsigned char* bitstreamAt = bitstream; + const unsigned char* bitstreamAt = bitstream; // If destination node is not included, set it to root if (!args.destinationNode) { @@ -330,9 +330,10 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); int theseBytesRead = 0; theseBytesRead += octalCodeBytes; + theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, bufferSizeBytes - (bytesRead + octalCodeBytes), args); - + // skip bitstream to new startPoint bitstreamAt += theseBytesRead; bytesRead += theseBytesRead; @@ -354,16 +355,16 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) { class DeleteVoxelCodeFromTreeArgs { public: - bool collapseEmptyTrees; - unsigned char* codeBuffer; - int lengthOfCode; - bool deleteLastChild; - bool pathChanged; + bool collapseEmptyTrees; + const unsigned char* codeBuffer; + int lengthOfCode; + bool deleteLastChild; + bool pathChanged; }; // Note: uses the codeColorBuffer format, but the color's are ignored, because // this only finds and deletes the node from the tree. -void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool collapseEmptyTrees) { +void VoxelTree::deleteVoxelCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees) { // recurse the tree while decoding the codeBuffer, once you find the node in question, recurse // back and implement color reaveraging, and marking of lastChanged DeleteVoxelCodeFromTreeArgs args; @@ -492,13 +493,13 @@ void VoxelTree::eraseAllVoxels() { class ReadCodeColorBufferToTreeArgs { public: - unsigned char* codeColorBuffer; - int lengthOfCode; - bool destructive; - bool pathChanged; + const unsigned char* codeColorBuffer; + int lengthOfCode; + bool destructive; + bool pathChanged; }; -void VoxelTree::readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive) { +void VoxelTree::readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive) { ReadCodeColorBufferToTreeArgs args; args.codeColorBuffer = codeColorBuffer; args.lengthOfCode = numberOfThreeBitSectionsInCode(codeColorBuffer); @@ -578,7 +579,7 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraD } } -void VoxelTree::processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes) { +void VoxelTree::processRemoveVoxelBitstream(const unsigned char* bitstream, int bufferSizeBytes) { //unsigned short int itemNumber = (*((unsigned short int*)&bitstream[sizeof(PACKET_HEADER)])); int numBytesPacketHeader = numBytesForPacketHeader(bitstream); @@ -1043,14 +1044,14 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, doneEncoding(node); return bytesWritten; } - + // write the octal code bool roomForOctalCode = false; // assume the worst int codeLength; if (params.chopLevels) { unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); roomForOctalCode = packet->startSubTree(newCode); - + if (newCode) { // old way... codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); @@ -1072,7 +1073,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // old way memcpy(outputBuffer, node->getOctalCode(), codeLength); } - + // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { doneEncoding(node); @@ -1562,22 +1563,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = false; // ??? } - // if we were unable to fit this level in our packet, then rewind and add it to the node bag for - // sending later... - if (!continueThisLevel) { - packet->discardLevel(thisLevelKey); - bag.insert(node); - - // don't need to check node here, because we can't get here with no node - if (params.stats) { - params.stats->didntFit(node); - } - - //printf("line: %d <> returning 0...\n",__LINE__); - return 0; - } - - if (keepDiggingDeeper) { + if (continueThisLevel && keepDiggingDeeper) { // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. // @@ -1596,9 +1582,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make // a single recursive pass in distance sorted order, but retain standard order in our encoded packet int recursiveSliceSizes[NUMBER_OF_CHILDREN]; - unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - unsigned char* recursiveSliceStartsOLD[NUMBER_OF_CHILDREN]; - unsigned char* firstRecursiveSlice = packet->getEndOfBuffer(); + const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; + const unsigned char* recursiveSliceStartsOLD[NUMBER_OF_CHILDREN]; + int firstRecursiveSliceOffset = packet->getUncompressedByteOffset(); unsigned char* firstRecursiveSliceOLD = outputBuffer; int allSlicesSize = 0; @@ -1612,7 +1598,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, int thisLevel = currentEncodeLevel; // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packet->getEndOfBuffer(); + recursiveSliceStarts[originalIndex] = packet->getUncompressedData() + packet->getUncompressedSize(); recursiveSliceStartsOLD[originalIndex] = outputBuffer; int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, @@ -1689,7 +1675,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisSliceSize = recursiveSliceSizes[originalIndex]; - unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; + const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); tempBufferTo += thisSliceSize; @@ -1697,8 +1683,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } // now that all slices are back in the correct order, copy them to the correct output buffer - memcpy(firstRecursiveSlice, &tempReshuffleBuffer[0], allSlicesSize); - + packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); // DO IT AGAIN FOR OLD WAY.... unsigned char* tempBufferToOLD = &tempReshuffleBuffer[0]; // this is our temporary destination @@ -1709,7 +1694,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisSliceSize = recursiveSliceSizes[originalIndex]; - unsigned char* thisSliceStartsOLD = recursiveSliceStartsOLD[originalIndex]; + const unsigned char* thisSliceStartsOLD = recursiveSliceStartsOLD[originalIndex]; memcpy(tempBufferToOLD, thisSliceStartsOLD, thisSliceSize); tempBufferToOLD += thisSliceSize; @@ -1723,6 +1708,21 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } // end keepDiggingDeeper + // if we were unable to fit this level in our packet, then rewind and add it to the node bag for + // sending later... + if (!continueThisLevel) { + packet->discardLevel(thisLevelKey); + bag.insert(node); + + // don't need to check node here, because we can't get here with no node + if (params.stats) { + params.stats->didntFit(node); + } + + //printf("line: %d <> returning 0...\n",__LINE__); + return 0; + } + return bytesAtThisLevel; } @@ -2059,26 +2059,26 @@ void VoxelTree::doneEncoding(VoxelNode* node) { emptyDeleteQueue(); } -void VoxelTree::startDeleting(unsigned char* code) { +void VoxelTree::startDeleting(const unsigned char* code) { pthread_mutex_lock(&_deleteSetLock); _codesBeingDeleted.insert(code); pthread_mutex_unlock(&_deleteSetLock); } -void VoxelTree::doneDeleting(unsigned char* code) { +void VoxelTree::doneDeleting(const unsigned char* code) { pthread_mutex_lock(&_deleteSetLock); _codesBeingDeleted.erase(code); pthread_mutex_unlock(&_deleteSetLock); } -bool VoxelTree::isEncoding(unsigned char* codeBuffer) { +bool VoxelTree::isEncoding(const unsigned char* codeBuffer) { pthread_mutex_lock(&_encodeSetLock); bool isEncoding = (_codesBeingEncoded.find(codeBuffer) != _codesBeingEncoded.end()); pthread_mutex_unlock(&_encodeSetLock); return isEncoding; } -void VoxelTree::queueForLaterDelete(unsigned char* codeBuffer) { +void VoxelTree::queueForLaterDelete(const unsigned char* codeBuffer) { pthread_mutex_lock(&_deletePendingSetLock); _codesPendingDelete.insert(codeBuffer); pthread_mutex_unlock(&_deletePendingSetLock); @@ -2086,8 +2086,8 @@ void VoxelTree::queueForLaterDelete(unsigned char* codeBuffer) { void VoxelTree::emptyDeleteQueue() { pthread_mutex_lock(&_deletePendingSetLock); - for (std::set::iterator i = _codesPendingDelete.begin(); i != _codesPendingDelete.end(); ++i) { - unsigned char* codeToDelete = *i; + for (std::set::iterator i = _codesPendingDelete.begin(); i != _codesPendingDelete.end(); ++i) { + const unsigned char* codeToDelete = *i; _codesBeingDeleted.erase(codeToDelete); deleteVoxelCodeFromTree(codeToDelete, COLLAPSE_EMPTY_TREE); } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index a079667af7..7e070dfe7f 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -144,10 +144,10 @@ public: void eraseAllVoxels(); - void processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args); - void readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive = false); - void deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); + void processRemoveVoxelBitstream(const unsigned char* bitstream, int bufferSizeBytes); + void readBitstreamToTree(const unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args); + void readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive = false); + void deleteVoxelCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); void printTreeForDebugging(VoxelNode* startNode); void reaverageVoxelColors(VoxelNode* startNode); @@ -231,8 +231,9 @@ private: static bool countVoxelsOperation(VoxelNode* node, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; - VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); - int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args); + VoxelNode* createMissingNode(VoxelNode* lastParentNode, const unsigned char* codeToReach); + int readNodeData(VoxelNode *destinationNode, const unsigned char* nodeData, + int bufferSizeBytes, ReadBitstreamToTreeParams& args); bool _isDirty; unsigned long int _nodesChangedFromBitstream; @@ -250,26 +251,26 @@ private: /// Called to indicate that a VoxelNode is done being encoded. void doneEncoding(VoxelNode* node); /// Is the Octal Code currently being deleted? - bool isEncoding(unsigned char* codeBuffer); + bool isEncoding(const unsigned char* codeBuffer); /// Octal Codes of any subtrees currently being deleted. While any of these codes is being deleted, ancestors and /// descendants of them can not be encoded. - std::set _codesBeingDeleted; + std::set _codesBeingDeleted; /// mutex lock to protect the deleting set pthread_mutex_t _deleteSetLock; /// Called to indicate that an octal code is in the process of being deleted. - void startDeleting(unsigned char* code); + void startDeleting(const unsigned char* code); /// Called to indicate that an octal code is done being deleted. - void doneDeleting(unsigned char* code); + void doneDeleting(const unsigned char* code); /// Octal Codes that were attempted to be deleted but couldn't be because they were actively being encoded, and were /// instead queued for later delete - std::set _codesPendingDelete; + std::set _codesPendingDelete; /// mutex lock to protect the deleting set pthread_mutex_t _deletePendingSetLock; /// Adds an Octal Code to the set of codes that needs to be deleted - void queueForLaterDelete(unsigned char* codeBuffer); + void queueForLaterDelete(const unsigned char* codeBuffer); /// flushes out any Octal Codes that had to be queued void emptyDeleteQueue(); From 00b345172954f6d55d9fb7dd3c96e095f2165865 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:11:06 -0800 Subject: [PATCH 22/77] properly handle update fails when encoding --- libraries/voxels/src/VoxelTree.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2064d3b47f..9c9fe9a029 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1533,11 +1533,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write the child exist bits if (continueThisLevel) { continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); - - if (!continueThisLevel) { - //printf("packet->appendBitMask(childrenExistInPacketBits) returned FALSE....\n"); - } - // old way... *writeToThisLevelBuffer = childrenExistInPacketBits; @@ -1558,9 +1553,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); outputBuffer += bytesAtThisLevel; availableBytes -= bytesAtThisLevel; - } else { - //printf("line: %d setting continueThisLevel = false\n",__LINE__); - continueThisLevel = false; // ??? } if (continueThisLevel && keepDiggingDeeper) { @@ -1651,12 +1643,16 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // repair the child exists mask *childExistsPlaceHolderOLD = childrenExistInPacketBits; - packet->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits); - + continueThisLevel = packet->updatePriorBitMask(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); } + + if (!continueThisLevel) { + break; // can't continue... + } // Note: no need to move the pointer, cause we already stored this } // end if (childTreeBytesOut == 0) @@ -1664,7 +1660,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } // end for // reshuffle here... - if (params.wantOcclusionCulling) { + if (continueThisLevel && params.wantOcclusionCulling) { unsigned char tempReshuffleBuffer[MAX_VOXEL_PACKET_SIZE]; unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination @@ -1683,7 +1679,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } // now that all slices are back in the correct order, copy them to the correct output buffer - packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); + continueThisLevel = packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); // DO IT AGAIN FOR OLD WAY.... unsigned char* tempBufferToOLD = &tempReshuffleBuffer[0]; // this is our temporary destination @@ -1704,8 +1700,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // now that all slices are back in the correct order, copy them to the correct output buffer memcpy(firstRecursiveSliceOLD, &tempReshuffleBuffer[0], allSlicesSize); } - - } // end keepDiggingDeeper // if we were unable to fit this level in our packet, then rewind and add it to the node bag for From 661152956a8e705db3d6025b456481c52ceca533 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:23:03 -0800 Subject: [PATCH 23/77] clean up comments --- libraries/voxels/src/VoxelPacket.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 38a1ef3568..38df68142e 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -4,6 +4,12 @@ // // Created by Brad Hefta-Gaub on 11/19/2013 // +// TO DO: +// +// * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. +// * add compression +// * improve semantics for "reshuffle" - current approach will work for now, but wouldn't work +// with RLE because the colors in the levels would get reordered // #ifndef __hifi__VoxelPacket__ @@ -32,6 +38,7 @@ public: /// ends a level without discarding it void endLevel(); + /// appends a bitmask to the end of the stream, may fail if new data stream is too long to fit in packet bool appendBitMask(unsigned char bitmask); /// updates the value of a bitmask from a previously appended portion of the uncompressed stream, might fail if the new @@ -42,6 +49,7 @@ public: /// Might fail if the new bytes would cause packet to be less compressed, or if offset and length was out of range. bool updatePriorBytes(int offset, const unsigned char* replacementBytes, int length); + /// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet bool appendColor(rgbColor color); /// returns a byte offset from beginning of the uncompressed stream based on offset from end. @@ -61,9 +69,6 @@ public: /// has some content been written to the packet bool hasContent() const { return (_bytesInUse > 0); } - // XXXBHG: TO DO... - // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. - private: /// appends raw bytes, might fail if byte would cause packet to be too large bool append(const unsigned char* data, int length); From b1a0ed6480d82cacc16da44d2f847c516c64b082 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:36:38 -0800 Subject: [PATCH 24/77] remove old buffer style approach to encoding --- .../src/VoxelSendThread.cpp | 5 +- libraries/voxels/src/VoxelTree.cpp | 111 +----------------- libraries/voxels/src/VoxelTree.h | 4 +- 3 files changed, 8 insertions(+), 112 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 7b95b2291e..cb96fd1570 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -384,10 +384,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, - _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, - &_tempPacket, - nodeData->nodeBag, params); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); if (bytesWritten > 0) { _encodedSomething = true; } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 9c9fe9a029..c9f2d4b044 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1024,7 +1024,6 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& } int VoxelTree::encodeTreeBitstream(VoxelNode* node, - unsigned char* outputBuffer, int availableBytes, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) { @@ -1053,25 +1052,14 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, roomForOctalCode = packet->startSubTree(newCode); if (newCode) { - // old way... - codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); - memcpy(outputBuffer, newCode, codeLength); - - // do this! delete newCode; } else { codeLength = 1; - - // old way.... - *outputBuffer = 0; // root } } else { // new way roomForOctalCode = packet->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); - - // old way - memcpy(outputBuffer, node->getOctalCode(), codeLength); } // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... @@ -1082,10 +1070,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, bytesWritten += codeLength; // keep track of byte count - // old way... - outputBuffer += codeLength; // move the pointer - availableBytes -= codeLength; // keep track or remaining space - 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 @@ -1094,7 +1078,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, packet, bag, params, currentEncodeLevel); + int childBytesWritten = encodeTreeBitstreamRecursion(node, packet, bag, params, currentEncodeLevel); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -1125,7 +1109,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, - unsigned char* outputBuffer, int availableBytes, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const { // How many bytes have we written so far at this level; @@ -1232,7 +1215,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf. // leaf occlusion is handled down below when we check child nodes if (params.wantOcclusionCulling && !node->isLeaf()) { - //node->printDebugDetails("upper section, params.wantOcclusionCulling... node="); AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); VoxelProjectedPolygon* voxelPolygon = new VoxelProjectedPolygon(params.viewFrustum->getProjectedPolygon(voxelBox)); @@ -1240,8 +1222,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion // culling and proceed as normal if (voxelPolygon->getAllInView()) { - //node->printDebugDetails("upper section, voxelPolygon->getAllInView() node="); - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); delete voxelPolygon; // cleanup if (result == OCCLUDED) { @@ -1267,15 +1247,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char childrenExistInTreeBits = 0; unsigned char childrenExistInPacketBits = 0; unsigned char childrenColoredBits = 0; - - const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); - const int BYTES_PER_COLOR = 3; - const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); - const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; + const int BYTES_PER_COLOR = 3; // Make our local buffer large enough to handle writing at this level in case we need to. - unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; - unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; int thisLevelKey = packet->startLevel(); int inViewCount = 0; @@ -1306,11 +1280,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.wantOcclusionCulling) { if (childNode) { - // chance to optimize, doesn't need to be actual distance!! Could be distance squared - //float distanceSquared = childNode->distanceSquareToPoint(point); - //qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); - //childNode->printDebugDetails(""); - float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; currentCount = insertIntoSortedArrays((void*)childNode, distance, i, @@ -1458,17 +1427,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } } - // old way... - *writeToThisLevelBuffer = childrenColoredBits; - writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer - bool continueThisLevel = true; continueThisLevel = packet->appendBitMask(childrenColoredBits); - if (!continueThisLevel) { - //printf("packet->appendBitMask(childrenColoredBits) returned FALSE....\n"); - } - if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count if (params.stats) { @@ -1489,14 +1450,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, continueThisLevel = packet->appendColor(color); if (!continueThisLevel) { - //printf("packet->appendColor() i=%d returned FALSE....\n", i); break; // no point in continuing } - // old way... - memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR); - writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color - bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color // don't need to check childNode here, because we can't get here with no childNode @@ -1511,17 +1467,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits if (continueThisLevel && params.includeExistsBits) { - - // old way... - *writeToThisLevelBuffer = childrenExistInTreeBits; - writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer - continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); - - if (!continueThisLevel) { - //printf("packet->appendBitMask(childrenExistInTreeBits) returned FALSE....\n"); - } - if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count if (params.stats) { @@ -1533,10 +1479,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write the child exist bits if (continueThisLevel) { continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); - - // old way... - *writeToThisLevelBuffer = childrenExistInPacketBits; - if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count if (params.stats) { @@ -1548,13 +1490,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // We only need to keep digging, if there is at least one child that is inView, and not a leaf. keepDiggingDeeper = (inViewNotLeafCount > 0); - // old way... - if (availableBytes >= bytesAtThisLevel) { - memcpy(outputBuffer, &thisLevelBuffer[0], bytesAtThisLevel); - outputBuffer += bytesAtThisLevel; - availableBytes -= bytesAtThisLevel; - } - if (continueThisLevel && keepDiggingDeeper) { // at this point, we need to iterate the children who are in view, even if not colored // and we need to determine if there's a deeper tree below them that we care about. @@ -1567,7 +1502,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packet->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); - unsigned char* childExistsPlaceHolderOLD = outputBuffer-sizeof(childrenExistInPacketBits); // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, @@ -1575,9 +1509,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // a single recursive pass in distance sorted order, but retain standard order in our encoded packet int recursiveSliceSizes[NUMBER_OF_CHILDREN]; const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - const unsigned char* recursiveSliceStartsOLD[NUMBER_OF_CHILDREN]; int firstRecursiveSliceOffset = packet->getUncompressedByteOffset(); - unsigned char* firstRecursiveSliceOLD = outputBuffer; int allSlicesSize = 0; // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so @@ -1591,12 +1523,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, int thisLevel = currentEncodeLevel; // remember this for reshuffling recursiveSliceStarts[originalIndex] = packet->getUncompressedData() + packet->getUncompressedSize(); - recursiveSliceStartsOLD[originalIndex] = outputBuffer; - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, - outputBuffer, availableBytes, - packet, bag, - params, thisLevel); + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); // remember this for reshuffling recursiveSliceSizes[originalIndex] = childTreeBytesOut; @@ -1631,10 +1559,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, bytesAtThisLevel += childTreeBytesOut; - //old way - availableBytes -= childTreeBytesOut; - outputBuffer += childTreeBytesOut; - // If we had previously started writing, and if the child DIDN'T write any bytes, // then we want to remove their bit from the childExistsPlaceHolder bitmask if (childTreeBytesOut == 0) { @@ -1642,7 +1566,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, childrenExistInPacketBits -= (1 << (7 - originalIndex)); // repair the child exists mask - *childExistsPlaceHolderOLD = childrenExistInPacketBits; continueThisLevel = packet->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits); // If this is the last of the child exists bits, then we're actually be rolling out the entire tree @@ -1680,25 +1603,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // now that all slices are back in the correct order, copy them to the correct output buffer continueThisLevel = packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); - - // DO IT AGAIN FOR OLD WAY.... - unsigned char* tempBufferToOLD = &tempReshuffleBuffer[0]; // this is our temporary destination - - // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree - // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them - // back into original distance order - for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - int thisSliceSize = recursiveSliceSizes[originalIndex]; - const unsigned char* thisSliceStartsOLD = recursiveSliceStartsOLD[originalIndex]; - - memcpy(tempBufferToOLD, thisSliceStartsOLD, thisSliceSize); - tempBufferToOLD += thisSliceSize; - } - } - - // now that all slices are back in the correct order, copy them to the correct output buffer - memcpy(firstRecursiveSliceOLD, &tempReshuffleBuffer[0], allSlicesSize); } } // end keepDiggingDeeper @@ -1921,7 +1825,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { nodeBag.insert(rootNode); } - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; bool lastPacketWritten = false; @@ -1931,7 +1834,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); unlock(); // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet @@ -1977,7 +1880,6 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); } - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; @@ -1988,7 +1890,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); - bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); @@ -2009,7 +1911,6 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); - static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static VoxelPacket packet; int bytesWritten = 0; @@ -2020,7 +1921,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &packet, nodeBag, params); + bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packet, nodeBag, params); // ask destination tree to read the bitstream bool wantImportProgress = true; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 7e070dfe7f..48c001a3d0 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -164,8 +164,7 @@ public: void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData=NULL); - int encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelPacket* packet, VoxelNodeBag& bag, + int encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } @@ -224,7 +223,6 @@ private: void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); int encodeTreeBitstreamRecursion(VoxelNode* node, - unsigned char* outputBuffer, int availableBytes, VoxelPacket* packet, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const; From 11d7cb64c2c625fd6521bff1939e89c35ce2b0cc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:42:11 -0800 Subject: [PATCH 25/77] switch back to qDebug --- libraries/shared/src/SharedUtil.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 82153ab887..99b24979cc 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -71,18 +71,18 @@ void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - printf("[ %d (%c): ", byte, byte); + qDebug("[ %d (%c): ", byte, byte); } else { - printf("[ %d (0x%x): ", byte, byte); + qDebug("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - printf("%d", byte >> (7 - i) & 1); + qDebug("%d", byte >> (7 - i) & 1); } - printf(" ] "); + qDebug(" ] "); if (withNewLine) { - printf("\n"); + qDebug("\n"); } } From 4c0569fc601b7c2a9cc2b74fd290f32b35bf9fe6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 13:55:21 -0800 Subject: [PATCH 26/77] removing compression from VoxelNodeData to eventually move it into VoxelPacket where it belongs --- interface/src/VoxelPacketProcessor.cpp | 15 +--- .../src/VoxelNodeData.cpp | 82 +------------------ .../voxel-server-library/src/VoxelNodeData.h | 10 +-- .../src/VoxelSendThread.cpp | 12 +-- libraries/voxels/src/VoxelPacket.cpp | 26 ++++++ libraries/voxels/src/VoxelTree.cpp | 2 +- 6 files changed, 39 insertions(+), 108 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 52f992d56b..93ae74cd99 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -58,20 +58,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* app->_environment.parseData(&senderAddress, packetData, messageLength); } else { app->_voxels.setDataSourceUUID(voxelServer->getUUID()); - - // these packets are commpressed... - if (VOXEL_PACKETS_COMPRESSED) { - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - QByteArray compressedData((const char*)packetData + numBytesPacketHeader, - messageLength - numBytesPacketHeader); - QByteArray uncompressedData = qUncompress(compressedData); - QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); - uncompressedPacket.append(uncompressedData); - - app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); - } else { - app->_voxels.parseData(packetData, messageLength); - } + app->_voxels.parseData(packetData, messageLength); app->_voxels.setDataSourceUUID(QUuid()); } } diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 1d42173e7d..d54d388431 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -30,11 +30,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lodChanged(false), _lodInitialized(false) { - if (VOXEL_PACKETS_COMPRESSED) { - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE; - } else { - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; - } + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; _voxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _voxelPacketAt = _voxelPacket; _lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; @@ -108,89 +104,15 @@ void VoxelNodeData::resetVoxelPacket() { int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - if (VOXEL_PACKETS_COMPRESSED) { - _voxelPacketAvailableBytes = (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - numBytesPacketHeader; - compressPacket(); - } else { - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; - } + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; _voxelPacketWaiting = false; } -bool VoxelNodeData::willFit(unsigned char* buffer, int bytes) { - bool wouldFit = false; - if (VOXEL_PACKETS_COMPRESSED) { - int uncompressedLength = getPacketLengthUncompressed(); - const int MAX_COMPRESSION = 9; - // we only want to compress the data payload, not the message header - int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); - - // start with the current uncompressed data - QByteArray uncompressedTestData((const char*)_voxelPacket + numBytesPacketHeader, - uncompressedLength - numBytesPacketHeader); - - // append this next buffer... - uncompressedTestData.append((const char*)buffer, bytes); - - // test compress it - QByteArray compressedData = qCompress(uncompressedTestData, MAX_COMPRESSION); - - wouldFit = (compressedData.size() + numBytesPacketHeader) <= MAX_VOXEL_PACKET_SIZE; - - /* - if (!wouldFit) { - printf("would not fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", - getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); - } else { - printf("would fit... previous size: %d, buffer size: %d, would be:%d MAX_VOXEL_PACKET_SIZE: %d\n", - getPacketLength(), bytes, (compressedData.size() + numBytesPacketHeader), MAX_VOXEL_PACKET_SIZE); - } - */ - } else { - wouldFit = bytes <= _voxelPacketAvailableBytes; - } - return wouldFit; -} - void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; _voxelPacketWaiting = true; - compressPacket(); -} - -const unsigned char* VoxelNodeData::getPacket() const { - if (VOXEL_PACKETS_COMPRESSED) { - return (const unsigned char*)_compressedPacket.constData(); - } - return _voxelPacket; -} - -int VoxelNodeData::getPacketLength() const { - if (VOXEL_PACKETS_COMPRESSED) { - return _compressedPacket.size(); - } - return getPacketLengthUncompressed(); -} - -int VoxelNodeData::getPacketLengthUncompressed() const { - if (VOXEL_PACKETS_COMPRESSED) { - return (MAX_VOXEL_PACKET_SIZE * UNCOMPRESSED_SIZE_MULTIPLE) - _voxelPacketAvailableBytes; - } - return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; -} - -void VoxelNodeData::compressPacket() { - int uncompressedLength = getPacketLengthUncompressed(); - const int MAX_COMPRESSION = 9; - // we only want to compress the data payload, not the message header - int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); - QByteArray compressedData = qCompress(_voxelPacket+numBytesPacketHeader, - uncompressedLength-numBytesPacketHeader, MAX_COMPRESSION); - _compressedPacket.clear(); - _compressedPacket.append((const char*)_voxelPacket, numBytesPacketHeader); - _compressedPacket.append(compressedData); } VoxelNodeData::~VoxelNodeData() { diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 92ae5fc6c8..b429ec5a90 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -29,11 +29,10 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet - bool willFit(unsigned char* buffer, int bytes); // tests to see if the bytes will fit + bool willFit(unsigned char* buffer, int bytes) { return (bytes <= _voxelPacketAvailableBytes); } - const unsigned char* getPacket() const; - int getPacketLength() const; - int getPacketLengthUncompressed() const; + const unsigned char* getPacket() const { return _voxelPacket; } + int getPacketLength() const { return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; } bool isPacketWaiting() const { return _voxelPacketWaiting; } @@ -112,9 +111,6 @@ private: float _lastClientVoxelSizeScale; bool _lodChanged; bool _lodInitialized; - - QByteArray _compressedPacket; - void compressPacket(); }; #endif /* defined(__hifi__VoxelNodeData__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index cb96fd1570..c0d6b90e4a 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -112,14 +112,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalUncompressed += nodeData->getPacketLength(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { qDebug("line: %d - Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", __LINE__, totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, thisWastedBytes, ::totalWastedBytes); } @@ -156,14 +156,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalUncompressed += nodeData->getPacketLength(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", __LINE__, totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, thisWastedBytes, ::totalWastedBytes); } @@ -179,14 +179,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLengthUncompressed(); + ::totalUncompressed += nodeData->getPacketLength(); ::totalCompressed += nodeData->getPacketLength(); ::totalPackets++; if (debug) { qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", __LINE__, totalPackets, - nodeData->getPacketLengthUncompressed(), ::totalUncompressed, + nodeData->getPacketLength(), ::totalUncompressed, nodeData->getPacketLength(), ::totalCompressed, thisWastedBytes, ::totalWastedBytes); } diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index e11ce46f51..68739ae65e 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -129,3 +129,29 @@ bool VoxelPacket::appendColor(rgbColor color) { return success; } +/*** +void VoxelPacket::compressPacket() { + int uncompressedLength = getPacketLengthUncompressed(); + const int MAX_COMPRESSION = 9; + // we only want to compress the data payload, not the message header + int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); + QByteArray compressedData = qCompress(_voxelPacket+numBytesPacketHeader, + uncompressedLength-numBytesPacketHeader, MAX_COMPRESSION); + _compressedPacket.clear(); + _compressedPacket.append((const char*)_voxelPacket, numBytesPacketHeader); + _compressedPacket.append(compressedData); +} + +void VoxelPacket::uncompressPacket() { + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + QByteArray compressedData((const char*)packetData + numBytesPacketHeader, + messageLength - numBytesPacketHeader); + QByteArray uncompressedData = qUncompress(compressedData); + QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); + uncompressedPacket.append(uncompressedData); + //app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); +} +***/ + + + diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c9f2d4b044..c499973831 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1247,7 +1247,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char childrenExistInTreeBits = 0; unsigned char childrenExistInPacketBits = 0; unsigned char childrenColoredBits = 0; - const int BYTES_PER_COLOR = 3; + const int BYTES_PER_COLOR = 3; // Make our local buffer large enough to handle writing at this level in case we need to. int thisLevelKey = packet->startLevel(); From ae5d5324c11a55ae0995002142eb72156f868b4d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:02:46 -0800 Subject: [PATCH 27/77] added some comments to VoxelPacket --- libraries/voxels/src/VoxelPacket.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 38df68142e..060fa4a653 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -8,8 +8,9 @@ // // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. // * add compression -// * improve semantics for "reshuffle" - current approach will work for now, but wouldn't work -// with RLE because the colors in the levels would get reordered +// * improve semantics for "reshuffle" - current approach will work for now and with compression +// but wouldn't work with RLE because the colors in the levels would get reordered and RLE would need +// to be recalculated // #ifndef __hifi__VoxelPacket__ @@ -24,9 +25,17 @@ public: VoxelPacket(); ~VoxelPacket(); + /// reset completely, all data is discarded void reset(); + + /// call to begin encoding a subtree starting at this point, this will append the octcode to the uncompressed stream + /// at this point. May fail if new datastream is too long. In failure case the stream remains in it's previous state. bool startSubTree(const unsigned char* octcode = NULL); + + // call to indicate that the current subtree is complete and changes should be committed. void endSubTree(); + + // call rollback the current subtree and restore the stream to the state prior to starting the subtree encoding void discardSubTree(); /// starts a level marker. returns an opaque key which can be used to discard the level From 29522d1e50dcb78dac1146e5ef3ebb3e2f1be0cc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:07:01 -0800 Subject: [PATCH 28/77] tweaks and cleanup --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 4 +--- libraries/voxel-server-library/src/VoxelNodeData.h | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index d54d388431..152bb6a78f 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -13,8 +13,6 @@ #include #include "VoxelSendThread.h" -const int UNCOMPRESSED_SIZE_MULTIPLE = 20; - VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelQuery(owningNode), _viewSent(false), @@ -47,7 +45,7 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { _voxelSendThread->initialize(true); } -bool VoxelNodeData::packetIsDuplicate() { +bool VoxelNodeData::packetIsDuplicate() const { if (_lastVoxelPacketLength == getPacketLength()) { return memcmp(_lastVoxelPacket, getPacket(), getPacketLength()) == 0; } diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index b429ec5a90..f19f80bd40 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -36,10 +36,10 @@ public: bool isPacketWaiting() const { return _voxelPacketWaiting; } - bool packetIsDuplicate(); + bool packetIsDuplicate() const; bool shouldSuppressDuplicatePacket(); - int getAvailable() const { return MAX_VOXEL_PACKET_SIZE - getPacketLength(); } + int getAvailable() const { return _voxelPacketAvailableBytes; } int getMaxSearchLevel() const { return _maxSearchLevel; }; void resetMaxSearchLevel() { _maxSearchLevel = 1; }; void incrementMaxSearchLevel() { _maxSearchLevel++; }; From 57831b377fb04c332efe50b1a12f8331e28b8464 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:07:09 -0800 Subject: [PATCH 29/77] tweaks and cleanup --- interface/src/VoxelPacketProcessor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 93ae74cd99..9087a5a545 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -8,8 +8,6 @@ // Threaded or non-threaded voxel packet receiver for the Application // -#include - #include #include "Application.h" From 0ed31b5b9f9b1dcea77e92311eb833f3273825da Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:14:00 -0800 Subject: [PATCH 30/77] tweaks and cleanup --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 1 - libraries/voxels/src/VoxelTree.cpp | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 152bb6a78f..773cd8c26e 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -101,7 +101,6 @@ void VoxelNodeData::resetVoxelPacket() { int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; _voxelPacketWaiting = false; } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index c499973831..3fdfb34910 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,8 +286,6 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, const unsigned char* nod // now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child // subtree/node, because it shouldn't actually exist in the tree. if (!oneAtBit(childrenInTreeMask, i) && destinationNode->getChildAtIndex(i)) { -printf("CALLING destinationNode->safeDeepDeleteChildAtIndex(i) because of EXISTS_BITS destinationNode->level=%d childIndex=%d\n", - destinationNode->getLevel(), i); destinationNode->safeDeepDeleteChildAtIndex(i); _isDirty = true; // by definition! } @@ -333,7 +331,7 @@ void VoxelTree::readBitstreamToTree(const unsigned char * bitstream, unsigned lo theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, bufferSizeBytes - (bytesRead + octalCodeBytes), args); - + // skip bitstream to new startPoint bitstreamAt += theseBytesRead; bytesRead += theseBytesRead; @@ -1617,7 +1615,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, params.stats->didntFit(node); } - //printf("line: %d <> returning 0...\n",__LINE__); return 0; } From 13e6a187bd9810a18b2514507f56415fc806e713 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:19:18 -0800 Subject: [PATCH 31/77] tweaks and cleanup --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 8 ++++---- libraries/voxel-server-library/src/VoxelNodeData.h | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 773cd8c26e..363f58fc8b 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -16,6 +16,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelQuery(owningNode), _viewSent(false), + _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), _maxSearchLevel(1), _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), @@ -28,7 +29,6 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lodChanged(false), _lodInitialized(false) { - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE; _voxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _voxelPacketAt = _voxelPacket; _lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; @@ -47,7 +47,7 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { bool VoxelNodeData::packetIsDuplicate() const { if (_lastVoxelPacketLength == getPacketLength()) { - return memcmp(_lastVoxelPacket, getPacket(), getPacketLength()) == 0; + return memcmp(_lastVoxelPacket, _voxelPacket, getPacketLength()) == 0; } return false; } @@ -67,7 +67,7 @@ bool VoxelNodeData::shouldSuppressDuplicatePacket() { // How long has it been since we've sent one, if we're still under our max time, then keep considering // this packet for suppression uint64_t now = usecTimestampNow(); - int sinceFirstSuppressedPacket = now - _firstSuppressedPacket; + long sinceFirstSuppressedPacket = now - _firstSuppressedPacket; const long MAX_TIME_BETWEEN_DUPLICATE_PACKETS = 1000 * 1000; // 1 second. if (sinceFirstSuppressedPacket < MAX_TIME_BETWEEN_DUPLICATE_PACKETS) { @@ -92,7 +92,7 @@ void VoxelNodeData::resetVoxelPacket() { // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. _lastVoxelPacketLength = getPacketLength(); - memcpy(_lastVoxelPacket, getPacket(), _lastVoxelPacketLength); + memcpy(_lastVoxelPacket, _voxelPacket, _lastVoxelPacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index f19f80bd40..d0f2d2f6b5 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -29,8 +29,6 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet - bool willFit(unsigned char* buffer, int bytes) { return (bytes <= _voxelPacketAvailableBytes); } - const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; } From 51547f6f8d1291a51a0ae251bdea2d71c77c7ff2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:20:12 -0800 Subject: [PATCH 32/77] tweaks and cleanup --- libraries/voxel-server-library/src/VoxelNodeData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index d0f2d2f6b5..c8466e4f9b 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -29,9 +29,9 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet + const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; } - bool isPacketWaiting() const { return _voxelPacketWaiting; } bool packetIsDuplicate() const; From a9642a3e15fae0c0ebb5beb5a854eb09bf62c662 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:21:14 -0800 Subject: [PATCH 33/77] tweaks and cleanup --- libraries/voxel-server-library/src/VoxelNodeData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index c8466e4f9b..c21b99a308 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -30,8 +30,8 @@ public: void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet - const unsigned char* getPacket() const { return _voxelPacket; } - int getPacketLength() const { return MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes; } + const unsigned char* getPacket() const { return _voxelPacket; } + int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } bool packetIsDuplicate() const; From a9f336e34e21be645683560b49dab4269f3fbaed Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:49:53 -0800 Subject: [PATCH 34/77] cleaned up packet sending accounting and debug output to be less verbose unless requested --- .../src/VoxelSendThread.cpp | 107 ++++++++---------- .../src/VoxelSendThread.h | 5 + 2 files changed, 52 insertions(+), 60 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index c0d6b90e4a..11874ed6c1 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -45,7 +45,7 @@ bool VoxelSendThread::process() { // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); } packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); @@ -55,7 +55,7 @@ bool VoxelSendThread::process() { } } } else { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { qDebug("VoxelSendThread::process() waiting for isInitialLoadComplete()\n"); } } @@ -69,7 +69,7 @@ bool VoxelSendThread::process() { if (usecToSleep > 0) { usleep(usecToSleep); } else { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { std::cout << "Last send took too much time, not sleeping!\n"; } } @@ -79,13 +79,12 @@ bool VoxelSendThread::process() { } -int totalUncompressed = 0; -int totalCompressed = 0; -int totalWastedBytes = 0; -int totalPackets = 0; +uint64_t VoxelSendThread::_totalBytes = 0; +uint64_t VoxelSendThread::_totalWastedBytes = 0; +uint64_t VoxelSendThread::_totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = true; + bool debug = _myServer->wantsDebugVoxelSending(); bool packetSent = false; // did we send a packet? int packetsSent = 0; @@ -111,17 +110,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& statsMessageLength += nodeData->getPacketLength(); int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data - ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLength(); - ::totalCompressed += nodeData->getPacketLength(); - ::totalPackets++; + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; if (debug) { - qDebug("line: %d - Adding stats to packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - __LINE__, - totalPackets, - nodeData->getPacketLength(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + qDebug("Adding stats to packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + _totalPackets, + nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); } // actually send it @@ -131,18 +127,15 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // not enough room in the packet, send two packets NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); - int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; - ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += statsMessageLength; - ::totalCompressed += statsMessageLength; - ::totalPackets++; + int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; if (debug) { - qDebug("line: %d - Sending separate stats packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - __LINE__, - totalPackets, - statsMessageLength, ::totalUncompressed, - statsMessageLength, ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + qDebug("Sending separate stats packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + _totalPackets, + nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); } trueBytesSent += statsMessageLength; @@ -155,17 +148,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& packetSent = true; thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); - ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLength(); - ::totalCompressed += nodeData->getPacketLength(); - ::totalPackets++; + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; if (debug) { - qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - __LINE__, - totalPackets, - nodeData->getPacketLength(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + qDebug("Sending packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + _totalPackets, + nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); } } nodeData->stats.markAsSent(); @@ -178,17 +168,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); - ::totalWastedBytes += thisWastedBytes; - ::totalUncompressed += nodeData->getPacketLength(); - ::totalCompressed += nodeData->getPacketLength(); - ::totalPackets++; + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; if (debug) { - qDebug("line: %d - Sending packet [%d]: uncompress size:%d [%d], compressed size:%d [%d] thisWastedBytes:%d [%d]\n", - __LINE__, - totalPackets, - nodeData->getPacketLength(), ::totalUncompressed, - nodeData->getPacketLength(), ::totalCompressed, - thisWastedBytes, ::totalWastedBytes); + qDebug("Sending packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + _totalPackets, + nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); } } } @@ -226,14 +213,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (wantColor != nodeData->getCurrentPacketIsColor()) { if (nodeData->isPacketWaiting()) { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); } @@ -241,7 +228,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } } - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); @@ -249,7 +236,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), debug::valueOf(nodeData->getViewSent()) @@ -260,7 +247,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { uint64_t now = usecTimestampNow(); - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); if (nodeData->getLastTimeBagEmpty() > 0) { @@ -330,14 +317,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxVoxelPacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); } while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); @@ -351,7 +338,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec); if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) { - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n", usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket, nodeData->nodeBag.count()); @@ -434,7 +421,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (_myServer->wantsDebugVoxelSending()) { + } else if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } @@ -444,13 +431,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (nodeData->nodeBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { nodeData->map.printStats(); } nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 304001845a..1c60be701d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -36,6 +36,11 @@ private: unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; VoxelPacket _tempPacket; bool _encodedSomething; + + static uint64_t _totalBytes; + static uint64_t _totalWastedBytes; + static uint64_t _totalPackets; + }; #endif // __voxel_server__VoxelSendThread__ From 7ff7b13c6bef621dea70d206ec43e862e35e10f7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:52:34 -0800 Subject: [PATCH 35/77] cleaned up some comments --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 2 +- libraries/voxels/src/VoxelTree.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 11874ed6c1..d7b007088b 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -127,7 +127,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // not enough room in the packet, send two packets NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); - int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data + int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength is only the stats _totalWastedBytes += thisWastedBytes; _totalBytes += nodeData->getPacketLength(); _totalPackets++; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3fdfb34910..5ac82697e8 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1055,7 +1055,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, codeLength = 1; } } else { - // new way roomForOctalCode = packet->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); } From b0cc6494daa068f02c68239bf203eedada303178 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 14:58:23 -0800 Subject: [PATCH 36/77] cleaned up some comments and code --- libraries/voxels/src/VoxelPacket.cpp | 8 ++++---- libraries/voxels/src/VoxelPacket.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 7 +------ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 68739ae65e..80060853f1 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -116,14 +116,14 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) { return success; } -bool VoxelPacket::appendColor(rgbColor color) { +bool VoxelPacket::appendColor(const nodeColor& color) { // eventually we can make this use a dictionary... bool success = false; const int BYTES_PER_COLOR = 3; if (_bytesAvailable > BYTES_PER_COLOR) { - append(color[0]); - append(color[1]); - append(color[2]); + append(color[RED_INDEX]); + append(color[GREEN_INDEX]); + append(color[BLUE_INDEX]); success = true; } return success; diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 060fa4a653..dca796de23 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -59,7 +59,7 @@ public: bool updatePriorBytes(int offset, const unsigned char* replacementBytes, int length); /// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet - bool appendColor(rgbColor color); + bool appendColor(const nodeColor& color); /// returns a byte offset from beginning of the uncompressed stream based on offset from end. /// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5ac82697e8..8acfac7318 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1439,12 +1439,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { VoxelNode* childNode = node->getChildAtIndex(i); - - rgbColor color; - color[0] = childNode->getColor()[0]; - color[1] = childNode->getColor()[1]; - color[2] = childNode->getColor()[2]; - continueThisLevel = packet->appendColor(color); + continueThisLevel = packet->appendColor(childNode->getColor()); if (!continueThisLevel) { break; // no point in continuing From cb43b0dea1991dbc7562b64cbf95cfc0dbd6c1fd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 15:10:03 -0800 Subject: [PATCH 37/77] cleaned up some comments and code --- libraries/voxels/src/VoxelTree.cpp | 2 -- voxel-edit/src/main.cpp | 4 ---- 2 files changed, 6 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8acfac7318..348e6a1899 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1832,7 +1832,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { // and reinsert the node in our bag and try again... if (bytesWritten == 0) { if (packet.hasContent()) { - printf("writeToSVOFile()... WRITING %d bytes...\n", packet.getFinalizedSize()); file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); lastPacketWritten = true; } @@ -1844,7 +1843,6 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { } if (!lastPacketWritten) { - printf("writeToSVOFile()... END OF LOOP WRITING %d bytes...\n", packet.getFinalizedSize()); file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); } diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index e24638389a..5f67a46163 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -45,7 +45,6 @@ void voxelTutorial(VoxelTree * tree) { node->getColor()[0], node->getColor()[1], node->getColor()[2]); } - /*** // here's an example of how to delete a voxel printf("attempting to delete corner point 0,0,0\n"); tree->deleteVoxelAt(0, 0, 0, voxelSize); @@ -56,7 +55,6 @@ void voxelTutorial(VoxelTree * tree) { } else { printf("corner point 0,0,0 does not exists...\n"); } - ***/ } @@ -352,9 +350,7 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); - printf("BEFORE writeToSVOFile()\n"); myTree.writeToSVOFile("voxels.svo"); - printf("AFTER writeToSVOFile()\n"); } return 0; From 99c427c97dfa112be75e359c89bc178e1f65ccbb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 16:18:18 -0800 Subject: [PATCH 38/77] cleaned up some comments and code --- libraries/shared/src/SharedUtil.cpp | 12 ++-- libraries/shared/src/SharedUtil.h | 2 +- .../src/VoxelNodeData.cpp | 2 +- .../voxel-server-library/src/VoxelNodeData.h | 2 +- libraries/voxels/src/VoxelPacket.cpp | 63 ++++++++++++++++--- libraries/voxels/src/VoxelPacket.h | 19 +++++- 6 files changed, 81 insertions(+), 19 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 99b24979cc..b9d5f9da60 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -60,7 +60,7 @@ bool shouldDo(float desiredInterval, float deltaTime) { return randFloat() < deltaTime / desiredInterval; } -void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { +void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) { for (int i = 0; i < length; i++) { outputBits(buffer[i], false); } @@ -71,18 +71,18 @@ void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - qDebug("[ %d (%c): ", byte, byte); + printf("[ %d (%c): ", byte, byte); } else { - qDebug("[ %d (0x%x): ", byte, byte); + printf("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - qDebug("%d", byte >> (7 - i) & 1); + printf("%d", byte >> (7 - i) & 1); } - qDebug(" ] "); + printf(" ] "); if (withNewLine) { - qDebug("\n"); + printf("\n"); } } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8f04ee15d5..29298ab944 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -52,7 +52,7 @@ bool randomBoolean(); bool shouldDo(float desiredInterval, float deltaTime); -void outputBufferBits(unsigned char* buffer, int length, bool withNewLine = true); +void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine = true); void outputBits(unsigned char byte, bool withNewLine = true); void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 363f58fc8b..6b7b704bf1 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -105,7 +105,7 @@ void VoxelNodeData::resetVoxelPacket() { _voxelPacketWaiting = false; } -void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { +void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index c21b99a308..373a6e0886 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -28,7 +28,7 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header - void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet + void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 80060853f1..385807e060 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -16,6 +16,10 @@ void VoxelPacket::reset() { _bytesInUse = 0; _bytesAvailable = MAX_VOXEL_PACKET_SIZE; _subTreeAt = 0; + _uncompressedData.clear(); + + //printf("VoxelPacket::reset()... "); + //debugCompareBuffers(); } VoxelPacket::~VoxelPacket() { @@ -25,10 +29,24 @@ bool VoxelPacket::append(const unsigned char* data, int length) { bool success = false; if (length <= _bytesAvailable) { + int priorBytesInUse = _bytesInUse; + memcpy(&_buffer[_bytesInUse], data, length); + //QByteArray newData((const char*)data, length); + //_uncompressedData.append(newData); + + _uncompressedData.resize(_bytesInUse+length); + char* writeable = _uncompressedData.data(); + memcpy(&writeable[_bytesInUse], data, length); + _bytesInUse += length; _bytesAvailable -= length; success = true; + + + //printf("VoxelPacket::append(data, length=%d... priorBytesInUse=%d)... ", length, priorBytesInUse); + debugCompareBuffers(); + } return success; } @@ -37,9 +55,16 @@ bool VoxelPacket::append(unsigned char byte) { bool success = false; if (_bytesAvailable > 0) { _buffer[_bytesInUse] = byte; + //_uncompressedData.append(byte); + _uncompressedData[_bytesInUse] = byte; + _bytesInUse++; _bytesAvailable--; success = true; + + //printf("VoxelPacket::append(byte)... "); + debugCompareBuffers(); + } return success; } @@ -48,7 +73,12 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { _buffer[offset] = bitmask; + _uncompressedData.replace(offset, sizeof(bitmask), (const char*)&bitmask, sizeof(bitmask)); success = true; + + //printf("VoxelPacket::updatePriorBitMask()... "); + debugCompareBuffers(); + } return success; } @@ -57,7 +87,12 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB bool success = false; if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { memcpy(&_buffer[offset], replacementBytes, length); + _uncompressedData.replace(offset, length, (const char*)replacementBytes, length); success = true; + + //printf("VoxelPacket::updatePriorBytes(offset=%d length=%d)...", offset, length); + debugCompareBuffers(); + } return success; } @@ -106,17 +141,12 @@ void VoxelPacket::endLevel() { } bool VoxelPacket::appendBitMask(unsigned char bitmask) { - bool success = false; - if (_bytesAvailable > 0) { - _buffer[_bytesInUse] = bitmask; - _bytesInUse++; - _bytesAvailable--; - success = true; - } - return success; + printf("VoxelPacket::appendBitMask()...\n"); + return append(bitmask); } bool VoxelPacket::appendColor(const nodeColor& color) { + printf("VoxelPacket::appendColor()...\n"); // eventually we can make this use a dictionary... bool success = false; const int BYTES_PER_COLOR = 3; @@ -153,5 +183,22 @@ void VoxelPacket::uncompressPacket() { } ***/ +void VoxelPacket::debugCompareBuffers() const { + const unsigned char* buffer = &_buffer[0]; + const unsigned char* byteArray = (const unsigned char*)_uncompressedData.constData(); + + if (memcmp(buffer, byteArray, _bytesInUse) == 0) { + //printf("VoxelPacket::debugCompareBuffers()... they match...\n"); + //printf("\n"); + } else { + printf("VoxelPacket::debugCompareBuffers()... THEY DON'T MATCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("_buffer="); + outputBufferBits(buffer, _bytesInUse); + printf("_uncompressedData="); + outputBufferBits(byteArray, _bytesInUse); + printf("VoxelPacket::debugCompareBuffers()... THEY DON'T MATCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } +} + diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index dca796de23..1753552aed 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -16,6 +16,8 @@ #ifndef __hifi__VoxelPacket__ #define __hifi__VoxelPacket__ +#include + #include #include "VoxelConstants.h" #include "VoxelNode.h" @@ -66,12 +68,20 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - unsigned char* getFinalizedData() { return &_buffer[0]; } + const unsigned char* getFinalizedData() { + debugCompareBuffers(); + return &_buffer[0]; + //return (const unsigned char*)_uncompressedData.constData(); + } /// get size of the finalized data (it may be compressed or rewritten into optimal form) int getFinalizedSize() const { return _bytesInUse; } /// get pointer to the start of uncompressed stream buffer - const unsigned char* getUncompressedData() { return &_buffer[0]; } + const unsigned char* getUncompressedData() { + debugCompareBuffers(); + return &_buffer[0]; + //return (const unsigned char*)_uncompressedData.constData(); + } /// the size of the packet in uncompressed form int getUncompressedSize() { return _bytesInUse; } @@ -85,10 +95,15 @@ private: /// append a single byte, might fail if byte would cause packet to be too large bool append(unsigned char byte); + QByteArray _uncompressedData; unsigned char _buffer[MAX_VOXEL_PACKET_SIZE]; + int _bytesInUse; int _bytesAvailable; int _subTreeAt; + + void debugCompareBuffers() const; + }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file From 0f66f4c1bd86aabacbc7230a084ee09b6cd9f1f7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 16:19:57 -0800 Subject: [PATCH 39/77] Revert "cleaned up some comments and code" This reverts commit 99c427c97dfa112be75e359c89bc178e1f65ccbb. --- libraries/shared/src/SharedUtil.cpp | 12 ++-- libraries/shared/src/SharedUtil.h | 2 +- .../src/VoxelNodeData.cpp | 2 +- .../voxel-server-library/src/VoxelNodeData.h | 2 +- libraries/voxels/src/VoxelPacket.cpp | 63 +++---------------- libraries/voxels/src/VoxelPacket.h | 19 +----- 6 files changed, 19 insertions(+), 81 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index b9d5f9da60..99b24979cc 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -60,7 +60,7 @@ bool shouldDo(float desiredInterval, float deltaTime) { return randFloat() < deltaTime / desiredInterval; } -void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) { +void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { for (int i = 0; i < length; i++) { outputBits(buffer[i], false); } @@ -71,18 +71,18 @@ void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - printf("[ %d (%c): ", byte, byte); + qDebug("[ %d (%c): ", byte, byte); } else { - printf("[ %d (0x%x): ", byte, byte); + qDebug("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - printf("%d", byte >> (7 - i) & 1); + qDebug("%d", byte >> (7 - i) & 1); } - printf(" ] "); + qDebug(" ] "); if (withNewLine) { - printf("\n"); + qDebug("\n"); } } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 29298ab944..8f04ee15d5 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -52,7 +52,7 @@ bool randomBoolean(); bool shouldDo(float desiredInterval, float deltaTime); -void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine = true); +void outputBufferBits(unsigned char* buffer, int length, bool withNewLine = true); void outputBits(unsigned char byte, bool withNewLine = true); void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 6b7b704bf1..363f58fc8b 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -105,7 +105,7 @@ void VoxelNodeData::resetVoxelPacket() { _voxelPacketWaiting = false; } -void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { +void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 373a6e0886..c21b99a308 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -28,7 +28,7 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header - void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet + void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 385807e060..80060853f1 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -16,10 +16,6 @@ void VoxelPacket::reset() { _bytesInUse = 0; _bytesAvailable = MAX_VOXEL_PACKET_SIZE; _subTreeAt = 0; - _uncompressedData.clear(); - - //printf("VoxelPacket::reset()... "); - //debugCompareBuffers(); } VoxelPacket::~VoxelPacket() { @@ -29,24 +25,10 @@ bool VoxelPacket::append(const unsigned char* data, int length) { bool success = false; if (length <= _bytesAvailable) { - int priorBytesInUse = _bytesInUse; - memcpy(&_buffer[_bytesInUse], data, length); - //QByteArray newData((const char*)data, length); - //_uncompressedData.append(newData); - - _uncompressedData.resize(_bytesInUse+length); - char* writeable = _uncompressedData.data(); - memcpy(&writeable[_bytesInUse], data, length); - _bytesInUse += length; _bytesAvailable -= length; success = true; - - - //printf("VoxelPacket::append(data, length=%d... priorBytesInUse=%d)... ", length, priorBytesInUse); - debugCompareBuffers(); - } return success; } @@ -55,16 +37,9 @@ bool VoxelPacket::append(unsigned char byte) { bool success = false; if (_bytesAvailable > 0) { _buffer[_bytesInUse] = byte; - //_uncompressedData.append(byte); - _uncompressedData[_bytesInUse] = byte; - _bytesInUse++; _bytesAvailable--; success = true; - - //printf("VoxelPacket::append(byte)... "); - debugCompareBuffers(); - } return success; } @@ -73,12 +48,7 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { _buffer[offset] = bitmask; - _uncompressedData.replace(offset, sizeof(bitmask), (const char*)&bitmask, sizeof(bitmask)); success = true; - - //printf("VoxelPacket::updatePriorBitMask()... "); - debugCompareBuffers(); - } return success; } @@ -87,12 +57,7 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB bool success = false; if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { memcpy(&_buffer[offset], replacementBytes, length); - _uncompressedData.replace(offset, length, (const char*)replacementBytes, length); success = true; - - //printf("VoxelPacket::updatePriorBytes(offset=%d length=%d)...", offset, length); - debugCompareBuffers(); - } return success; } @@ -141,12 +106,17 @@ void VoxelPacket::endLevel() { } bool VoxelPacket::appendBitMask(unsigned char bitmask) { - printf("VoxelPacket::appendBitMask()...\n"); - return append(bitmask); + bool success = false; + if (_bytesAvailable > 0) { + _buffer[_bytesInUse] = bitmask; + _bytesInUse++; + _bytesAvailable--; + success = true; + } + return success; } bool VoxelPacket::appendColor(const nodeColor& color) { - printf("VoxelPacket::appendColor()...\n"); // eventually we can make this use a dictionary... bool success = false; const int BYTES_PER_COLOR = 3; @@ -183,22 +153,5 @@ void VoxelPacket::uncompressPacket() { } ***/ -void VoxelPacket::debugCompareBuffers() const { - const unsigned char* buffer = &_buffer[0]; - const unsigned char* byteArray = (const unsigned char*)_uncompressedData.constData(); - - if (memcmp(buffer, byteArray, _bytesInUse) == 0) { - //printf("VoxelPacket::debugCompareBuffers()... they match...\n"); - //printf("\n"); - } else { - printf("VoxelPacket::debugCompareBuffers()... THEY DON'T MATCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - printf("_buffer="); - outputBufferBits(buffer, _bytesInUse); - printf("_uncompressedData="); - outputBufferBits(byteArray, _bytesInUse); - printf("VoxelPacket::debugCompareBuffers()... THEY DON'T MATCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - } -} - diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 1753552aed..dca796de23 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -16,8 +16,6 @@ #ifndef __hifi__VoxelPacket__ #define __hifi__VoxelPacket__ -#include - #include #include "VoxelConstants.h" #include "VoxelNode.h" @@ -68,20 +66,12 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - const unsigned char* getFinalizedData() { - debugCompareBuffers(); - return &_buffer[0]; - //return (const unsigned char*)_uncompressedData.constData(); - } + unsigned char* getFinalizedData() { return &_buffer[0]; } /// get size of the finalized data (it may be compressed or rewritten into optimal form) int getFinalizedSize() const { return _bytesInUse; } /// get pointer to the start of uncompressed stream buffer - const unsigned char* getUncompressedData() { - debugCompareBuffers(); - return &_buffer[0]; - //return (const unsigned char*)_uncompressedData.constData(); - } + const unsigned char* getUncompressedData() { return &_buffer[0]; } /// the size of the packet in uncompressed form int getUncompressedSize() { return _bytesInUse; } @@ -95,15 +85,10 @@ private: /// append a single byte, might fail if byte would cause packet to be too large bool append(unsigned char byte); - QByteArray _uncompressedData; unsigned char _buffer[MAX_VOXEL_PACKET_SIZE]; - int _bytesInUse; int _bytesAvailable; int _subTreeAt; - - void debugCompareBuffers() const; - }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file From cd1d3765a918b0d562e9cf5c0f7c19cefbb92765 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 16:28:21 -0800 Subject: [PATCH 40/77] cleaned up const semantics and DRYed up appendBitMask --- libraries/shared/src/SharedUtil.cpp | 2 +- libraries/shared/src/SharedUtil.h | 2 +- libraries/voxel-server-library/src/VoxelNodeData.cpp | 2 +- libraries/voxel-server-library/src/VoxelNodeData.h | 2 +- libraries/voxels/src/VoxelPacket.cpp | 9 +-------- libraries/voxels/src/VoxelPacket.h | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 99b24979cc..8c56c250e0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -60,7 +60,7 @@ bool shouldDo(float desiredInterval, float deltaTime) { return randFloat() < deltaTime / desiredInterval; } -void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { +void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) { for (int i = 0; i < length; i++) { outputBits(buffer[i], false); } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8f04ee15d5..29298ab944 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -52,7 +52,7 @@ bool randomBoolean(); bool shouldDo(float desiredInterval, float deltaTime); -void outputBufferBits(unsigned char* buffer, int length, bool withNewLine = true); +void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine = true); void outputBits(unsigned char byte, bool withNewLine = true); void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 363f58fc8b..6b7b704bf1 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -105,7 +105,7 @@ void VoxelNodeData::resetVoxelPacket() { _voxelPacketWaiting = false; } -void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { +void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index c21b99a308..373a6e0886 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -28,7 +28,7 @@ public: void resetVoxelPacket(); // resets voxel packet to after "V" header - void writeToPacket(unsigned char* buffer, int bytes); // writes to end of packet + void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 80060853f1..657f2a99be 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -106,14 +106,7 @@ void VoxelPacket::endLevel() { } bool VoxelPacket::appendBitMask(unsigned char bitmask) { - bool success = false; - if (_bytesAvailable > 0) { - _buffer[_bytesInUse] = bitmask; - _bytesInUse++; - _bytesAvailable--; - success = true; - } - return success; + return append(bitmask); } bool VoxelPacket::appendColor(const nodeColor& color) { diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index dca796de23..66591bd568 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -66,7 +66,7 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - unsigned char* getFinalizedData() { return &_buffer[0]; } + const unsigned char* getFinalizedData() { return &_buffer[0]; } /// get size of the finalized data (it may be compressed or rewritten into optimal form) int getFinalizedSize() const { return _bytesInUse; } From e65f74e06b6efa94b59f91c08e3620f39a25630b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 21:40:50 -0800 Subject: [PATCH 41/77] moved compression into VoxelPacket class. works, but too slow for larger sizes --- interface/src/VoxelSystem.cpp | 12 +- libraries/shared/src/OctalCode.cpp | 4 +- libraries/shared/src/SharedUtil.cpp | 10 +- .../src/VoxelSendThread.cpp | 8 + .../src/VoxelSendThread.h | 2 +- libraries/voxels/src/VoxelConstants.h | 3 + libraries/voxels/src/VoxelPacket.cpp | 153 ++++++++++++++++-- libraries/voxels/src/VoxelPacket.h | 20 ++- libraries/voxels/src/VoxelTree.cpp | 2 +- 9 files changed, 184 insertions(+), 30 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 62419565c6..21e7809014 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -597,7 +597,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); - _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); + VoxelPacket packet; + int compressedSize = numBytes - numBytesPacketHeader; + packet.loadCompressedContent(voxelData, compressedSize); +printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); unlockTree(); } break; @@ -607,7 +611,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { // ask the VoxelTree to read the MONOCHROME bitstream into the tree ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); - _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); + VoxelPacket packet; + int compressedSize = numBytes - numBytesPacketHeader; + packet.loadCompressedContent(voxelData, compressedSize); +printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); unlockTree(); } break; diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 027a6a4d68..5f79a7dfa5 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -32,12 +32,12 @@ int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) void printOctalCode(const unsigned char* octalCode) { if (!octalCode) { - qDebug("NULL\n"); + printf("NULL\n"); } else { for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { outputBits(octalCode[i],false); } - qDebug("\n"); + printf("\n"); } } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 8c56c250e0..b9d5f9da60 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -71,18 +71,18 @@ void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - qDebug("[ %d (%c): ", byte, byte); + printf("[ %d (%c): ", byte, byte); } else { - qDebug("[ %d (0x%x): ", byte, byte); + printf("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - qDebug("%d", byte >> (7 - i) & 1); + printf("%d", byte >> (7 - i) & 1); } - qDebug(" ] "); + printf(" ] "); if (withNewLine) { - qDebug("\n"); + printf("\n"); } } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index d7b007088b..de4d592a98 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -371,7 +371,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); + //printf("calling nodeBag.count()=%d encode()... subTree=%p \n", nodeData->nodeBag.count(), subTree); + //printOctalCode(subTree->getOctalCode()); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); + + + //printf("called encode()... bytesWritten=%d compressedSize=%d uncompressedSize=%d\n",bytesWritten, _tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); + if (bytesWritten > 0) { _encodedSomething = true; } @@ -388,6 +395,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // mean we should send the previous packet contents and reset it. bool sendNow = (bytesWritten == 0); if (_tempPacket.hasContent() && sendNow) { + printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",_tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 1c60be701d..607e1a9e0d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -33,7 +33,7 @@ private: int handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent); int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged); - unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; + unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; // used by environment sending code VoxelPacket _tempPacket; bool _encodedSomething; diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 0151789c4e..f2fa4eca92 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -35,6 +35,9 @@ const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); +const int MAX_VOXEL_PACKET_COMPRESSION_RATIO = 1; +const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_SIZE * MAX_VOXEL_PACKET_COMPRESSION_RATIO; + const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; // 6 sides * 4 corners per side diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 657f2a99be..5031e2b89e 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -14,8 +14,9 @@ VoxelPacket::VoxelPacket() { void VoxelPacket::reset() { _bytesInUse = 0; - _bytesAvailable = MAX_VOXEL_PACKET_SIZE; + _bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE; _subTreeAt = 0; + _compressedBytes = 0; } VoxelPacket::~VoxelPacket() { @@ -25,10 +26,18 @@ bool VoxelPacket::append(const unsigned char* data, int length) { bool success = false; if (length <= _bytesAvailable) { - memcpy(&_buffer[_bytesInUse], data, length); + memcpy(&_uncompressed[_bytesInUse], data, length); _bytesInUse += length; _bytesAvailable -= length; - success = true; + + // Now, check for compression, if we fit, then proceed, otherwise, rollback. + if (checkCompress()) { + success = true; + } else { + // rollback is easy, we just reset _bytesInUse and _bytesAvailable + _bytesInUse -= length; + _bytesAvailable += length; + } } return success; } @@ -36,10 +45,18 @@ bool VoxelPacket::append(const unsigned char* data, int length) { bool VoxelPacket::append(unsigned char byte) { bool success = false; if (_bytesAvailable > 0) { - _buffer[_bytesInUse] = byte; + _uncompressed[_bytesInUse] = byte; _bytesInUse++; _bytesAvailable--; - success = true; + + // Now, check for compression, if we fit, then proceed, otherwise, rollback. + if (checkCompress()) { + success = true; + } else { + // rollback is easy, we just reset _bytesInUse and _bytesAvailable + _bytesInUse--; + _bytesAvailable++; + } } return success; } @@ -47,8 +64,15 @@ bool VoxelPacket::append(unsigned char byte) { bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { - _buffer[offset] = bitmask; - success = true; + unsigned char oldValue = _uncompressed[offset]; + _uncompressed[offset] = bitmask; + // Now, check for compression, if we fit, then proceed, otherwise, rollback. + if (checkCompress()) { + success = true; + } else { + // rollback is easy, the length didn't change, but we need to restore the previous value + _uncompressed[offset] = oldValue; + } } return success; } @@ -56,8 +80,17 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) { bool success = false; if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { - memcpy(&_buffer[offset], replacementBytes, length); - success = true; + unsigned char oldValues[length]; + memcpy(&oldValues[0], &_uncompressed[offset], length); // save the old values for restore + memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content + + // Now, check for compression, if we fit, then proceed, otherwise, rollback. + if (checkCompress()) { + success = true; + } else { + // rollback is easy, the length didn't change, but we need to restore the previous values + memcpy(&_uncompressed[offset], &oldValues[0], length); // restore the old values + } } return success; } @@ -67,11 +100,11 @@ bool VoxelPacket::startSubTree(const unsigned char* octcode) { int possibleStartAt = _bytesInUse; if (octcode) { int length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode)); - success = append(octcode, length); + success = append(octcode, length); // handles checking compression } else { // NULL case, means root node, which is 0 unsigned char byte = 0; - success = append(byte); + success = append(byte); // handles checking compression } if (success) { _subTreeAt = possibleStartAt; @@ -88,6 +121,11 @@ void VoxelPacket::discardSubTree() { _bytesInUse -= bytesInSubTree; _bytesAvailable += bytesInSubTree; _subTreeAt = _bytesInUse; // should be the same actually... + + // we can be confident that it will compress, because we can't get here without previously being able to compress + // the content up to this point in the uncompressed buffer. But we still call this because it cleans up the compressed + // buffer with the correct content + checkCompress(); } int VoxelPacket::startLevel() { @@ -99,6 +137,11 @@ void VoxelPacket::discardLevel(int key) { int bytesInLevel = _bytesInUse - key; _bytesInUse -= bytesInLevel; _bytesAvailable += bytesInLevel; + + // we can be confident that it will compress, because we can't get here without previously being able to compress + // the content up to this point in the uncompressed buffer. But we still call this because it cleans up the compressed + // buffer with the correct content + checkCompress(); } void VoxelPacket::endLevel() { @@ -106,7 +149,7 @@ void VoxelPacket::endLevel() { } bool VoxelPacket::appendBitMask(unsigned char bitmask) { - return append(bitmask); + return append(bitmask); // handles checking compression } bool VoxelPacket::appendColor(const nodeColor& color) { @@ -114,14 +157,94 @@ bool VoxelPacket::appendColor(const nodeColor& color) { bool success = false; const int BYTES_PER_COLOR = 3; if (_bytesAvailable > BYTES_PER_COLOR) { - append(color[RED_INDEX]); - append(color[GREEN_INDEX]); - append(color[BLUE_INDEX]); + // handles checking compression... + if (append(color[RED_INDEX])) { + if (append(color[GREEN_INDEX])) { + if (append(color[BLUE_INDEX])) { + success = true; + } + } + } + } + return success; +} + +bool VoxelPacket::checkCompress() { + bool success = false; + const int MAX_COMPRESSION = 9; + + // we only want to compress the data payload, not the message header + QByteArray compressedData = qCompress(_uncompressed,_bytesInUse, MAX_COMPRESSION); + if (compressedData.size() < MAX_VOXEL_PACKET_SIZE) { + //memcpy(&_compressed[0], compressedData.constData(), compressedData.size()); + + _compressedBytes = compressedData.size(); + for (int i = 0; i < _compressedBytes; i++) { + _compressed[i] = compressedData[i]; + } + +//printf("compressed %d bytes from %d original bytes\n", _compressedBytes, _bytesInUse); success = true; } return success; } + +void VoxelPacket::loadCompressedContent(const unsigned char* data, int length) { + reset(); // by definition we reset upon loading compressed content + + if (length > 0) { + QByteArray compressedData; + + for (int i = 0; i < length; i++) { + compressedData[i] = data[i]; + _compressed[i] = compressedData[i]; + } + _compressedBytes = length; + + QByteArray uncompressedData = qUncompress(compressedData); + + if (uncompressedData.size() <= _bytesAvailable) { + _bytesInUse = uncompressedData.size(); + _bytesAvailable -= uncompressedData.size(); + + for (int i = 0; i < _bytesInUse; i++) { + _uncompressed[i] = uncompressedData[i]; + } + } + } else { + printf("VoxelPacket::loadCompressedContent()... length = 0, nothing to do...\n"); + } +} + +void VoxelPacket::debugContent() { + + printf("VoxelPacket::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes); + int perline=0; + for (int i = 0; i < _compressedBytes; i++) { + printf("%.2x ",_compressed[i]); + perline++; + if (perline >= 30) { + printf("\n"); + perline=0; + } + } + printf("\n"); + + printf("VoxelPacket::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse); + perline=0; + for (int i = 0; i < _bytesInUse; i++) { + printf("%.2x ",_uncompressed[i]); + perline++; + if (perline >= 30) { + printf("\n"); + perline=0; + } + } + printf("\n"); +} + + /*** void VoxelPacket::compressPacket() { int uncompressedLength = getPacketLengthUncompressed(); diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 66591bd568..c557726324 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -20,6 +20,8 @@ #include "VoxelConstants.h" #include "VoxelNode.h" + + class VoxelPacket { public: VoxelPacket(); @@ -66,17 +68,22 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - const unsigned char* getFinalizedData() { return &_buffer[0]; } + const unsigned char* getFinalizedData() { return &_compressed[0]; } /// get size of the finalized data (it may be compressed or rewritten into optimal form) - int getFinalizedSize() const { return _bytesInUse; } + int getFinalizedSize() const { return _compressedBytes; } /// get pointer to the start of uncompressed stream buffer - const unsigned char* getUncompressedData() { return &_buffer[0]; } + const unsigned char* getUncompressedData() { return &_uncompressed[0]; } /// the size of the packet in uncompressed form int getUncompressedSize() { return _bytesInUse; } /// has some content been written to the packet bool hasContent() const { return (_bytesInUse > 0); } + + /// load compressed content to allow access to decoded content for parsing + void loadCompressedContent(const unsigned char* data, int length); + + void debugContent(); private: /// appends raw bytes, might fail if byte would cause packet to be too large @@ -85,10 +92,15 @@ private: /// append a single byte, might fail if byte would cause packet to be too large bool append(unsigned char byte); - unsigned char _buffer[MAX_VOXEL_PACKET_SIZE]; + unsigned char _uncompressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; int _bytesAvailable; int _subTreeAt; + + bool checkCompress(); + + unsigned char _compressed[MAX_VOXEL_PACKET_SIZE]; + int _compressedBytes; }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 348e6a1899..e301cbc4cd 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1576,7 +1576,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // reshuffle here... if (continueThisLevel && params.wantOcclusionCulling) { - unsigned char tempReshuffleBuffer[MAX_VOXEL_PACKET_SIZE]; + unsigned char tempReshuffleBuffer[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination From c28027b7ca5153c491fe48cc993288f3a06e7ba9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 23 Nov 2013 22:30:15 -0800 Subject: [PATCH 42/77] better compressed packets with fewer calls to checkCompress --- .../src/VoxelSendThread.cpp | 14 ++++- libraries/voxels/src/VoxelConstants.h | 2 +- libraries/voxels/src/VoxelPacket.cpp | 60 +++++++++---------- libraries/voxels/src/VoxelPacket.h | 12 +++- libraries/voxels/src/VoxelTree.cpp | 8 ++- 5 files changed, 58 insertions(+), 38 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index de4d592a98..391722ce7f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -311,6 +311,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; uint64_t start = usecTimestampNow(); + uint64_t startCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; + uint64_t startCompressCalls = VoxelPacket::_checkCompressCalls; bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); @@ -429,9 +431,15 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", - elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + } else if (truePacketsSent > 0 /*_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()*/) { + + uint64_t endCompressCalls = VoxelPacket::_checkCompressCalls; + int elapsedCompressCalls = endCompressCalls - startCompressCalls; + + uint64_t endCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; + int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; + printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", + elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } // if after sending packets we've emptied our bag, then we want to remember that we've sent all diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index f2fa4eca92..c30d39dbf1 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -35,7 +35,7 @@ const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); -const int MAX_VOXEL_PACKET_COMPRESSION_RATIO = 1; +const int MAX_VOXEL_PACKET_COMPRESSION_RATIO = 3; const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_SIZE * MAX_VOXEL_PACKET_COMPRESSION_RATIO; const int MAX_TREE_SLICE_BYTES = 26; diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 5031e2b89e..d1405cd1e6 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -6,6 +6,7 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include #include "VoxelPacket.h" VoxelPacket::VoxelPacket() { @@ -30,6 +31,9 @@ bool VoxelPacket::append(const unsigned char* data, int length) { _bytesInUse += length; _bytesAvailable -= length; + success = true; + + /**** // Now, check for compression, if we fit, then proceed, otherwise, rollback. if (checkCompress()) { success = true; @@ -38,6 +42,7 @@ bool VoxelPacket::append(const unsigned char* data, int length) { _bytesInUse -= length; _bytesAvailable += length; } + ***/ } return success; } @@ -49,6 +54,9 @@ bool VoxelPacket::append(unsigned char byte) { _bytesInUse++; _bytesAvailable--; + success = true; + + /**** // Now, check for compression, if we fit, then proceed, otherwise, rollback. if (checkCompress()) { success = true; @@ -57,6 +65,7 @@ bool VoxelPacket::append(unsigned char byte) { _bytesInUse--; _bytesAvailable++; } + ****/ } return success; } @@ -66,6 +75,10 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { if (offset >= 0 && offset < _bytesInUse) { unsigned char oldValue = _uncompressed[offset]; _uncompressed[offset] = bitmask; + + success = true; + + /**** // Now, check for compression, if we fit, then proceed, otherwise, rollback. if (checkCompress()) { success = true; @@ -73,6 +86,7 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { // rollback is easy, the length didn't change, but we need to restore the previous value _uncompressed[offset] = oldValue; } + ****/ } return success; } @@ -84,6 +98,9 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB memcpy(&oldValues[0], &_uncompressed[offset], length); // save the old values for restore memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content + success = true; + + /**** // Now, check for compression, if we fit, then proceed, otherwise, rollback. if (checkCompress()) { success = true; @@ -91,6 +108,7 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB // rollback is easy, the length didn't change, but we need to restore the previous values memcpy(&_uncompressed[offset], &oldValues[0], length); // restore the old values } + ****/ } return success; } @@ -144,8 +162,12 @@ void VoxelPacket::discardLevel(int key) { checkCompress(); } -void VoxelPacket::endLevel() { - // nothing to do +bool VoxelPacket::endLevel(int key) { + bool success = checkCompress(); + if (!success) { + discardLevel(key); + } + return success; } bool VoxelPacket::appendBitMask(unsigned char bitmask) { @@ -169,7 +191,13 @@ bool VoxelPacket::appendColor(const nodeColor& color) { return success; } +uint64_t VoxelPacket::_checkCompressTime = 0; +uint64_t VoxelPacket::_checkCompressCalls = 0; + bool VoxelPacket::checkCompress() { + PerformanceWarning warn(false,"VoxelPacket::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls); + + bool success = false; const int MAX_COMPRESSION = 9; @@ -243,31 +271,3 @@ void VoxelPacket::debugContent() { } printf("\n"); } - - -/*** -void VoxelPacket::compressPacket() { - int uncompressedLength = getPacketLengthUncompressed(); - const int MAX_COMPRESSION = 9; - // we only want to compress the data payload, not the message header - int numBytesPacketHeader = numBytesForPacketHeader(_voxelPacket); - QByteArray compressedData = qCompress(_voxelPacket+numBytesPacketHeader, - uncompressedLength-numBytesPacketHeader, MAX_COMPRESSION); - _compressedPacket.clear(); - _compressedPacket.append((const char*)_voxelPacket, numBytesPacketHeader); - _compressedPacket.append(compressedData); -} - -void VoxelPacket::uncompressPacket() { - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - QByteArray compressedData((const char*)packetData + numBytesPacketHeader, - messageLength - numBytesPacketHeader); - QByteArray uncompressedData = qUncompress(compressedData); - QByteArray uncompressedPacket((const char*)packetData, numBytesPacketHeader); - uncompressedPacket.append(uncompressedData); - //app->_voxels.parseData((unsigned char*)uncompressedPacket.data(), uncompressedPacket.size()); -} -***/ - - - diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index c557726324..037b49e9ba 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -46,8 +46,9 @@ public: /// discards all content back to a previous marker key void discardLevel(int key); - /// ends a level without discarding it - void endLevel(); + /// ends a level, and performs any expensive finalization. may fail if finalization creates a stream which is too large + /// if the finalization would fail, the packet will automatically discard the previous level. + bool endLevel(int key); /// appends a bitmask to the end of the stream, may fail if new data stream is too long to fit in packet bool appendBitMask(unsigned char bitmask); @@ -84,7 +85,10 @@ public: void loadCompressedContent(const unsigned char* data, int length); void debugContent(); - + + static uint64_t _checkCompressTime; + static uint64_t _checkCompressCalls; + private: /// appends raw bytes, might fail if byte would cause packet to be too large bool append(const unsigned char* data, int length); @@ -101,6 +105,8 @@ private: unsigned char _compressed[MAX_VOXEL_PACKET_SIZE]; int _compressedBytes; + + }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index e301cbc4cd..8ef2cd7d66 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1600,8 +1600,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... - if (!continueThisLevel) { + + if (continueThisLevel) { + continueThisLevel = packet->endLevel(thisLevelKey); + } else { packet->discardLevel(thisLevelKey); + } + + if (!continueThisLevel) { bag.insert(node); // don't need to check node here, because we can't get here with no node From ba26e5c3e32a298ab9e16eaea0f5687bf441563b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 00:02:51 -0800 Subject: [PATCH 43/77] add back non-compression mode to VoxelPacket and tweaks to how compression works to make it more efficient --- .../src/VoxelSendThread.cpp | 2 +- libraries/voxels/src/VoxelConstants.h | 3 +- libraries/voxels/src/VoxelPacket.cpp | 176 +++++++++--------- libraries/voxels/src/VoxelPacket.h | 19 +- 4 files changed, 108 insertions(+), 92 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 391722ce7f..5d96cedb5d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -397,7 +397,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // mean we should send the previous packet contents and reset it. bool sendNow = (bytesWritten == 0); if (_tempPacket.hasContent() && sendNow) { - printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",_tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); + //printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",_tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index c30d39dbf1..e53107f80e 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -36,7 +36,8 @@ const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); const int MAX_VOXEL_PACKET_COMPRESSION_RATIO = 3; -const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_SIZE * MAX_VOXEL_PACKET_COMPRESSION_RATIO; +const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 3000; // MAX_VOXEL_PACKET_SIZE * MAX_VOXEL_PACKET_COMPRESSION_RATIO; +const int COMPRESSION_TEST_THRESHOLD = 2000; const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index d1405cd1e6..9911055d3c 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -9,15 +9,25 @@ #include #include "VoxelPacket.h" -VoxelPacket::VoxelPacket() { +bool VoxelPacket::_debug = false; + + +VoxelPacket::VoxelPacket(bool enableCompression, int maxFinalizedSize) { + _enableCompression = enableCompression; + _maxFinalizedSize = maxFinalizedSize; reset(); } void VoxelPacket::reset() { _bytesInUse = 0; - _bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE; + if (_enableCompression) { + _bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE; + } else { + _bytesAvailable = _maxFinalizedSize; + } _subTreeAt = 0; _compressedBytes = 0; + _dirty = false; } VoxelPacket::~VoxelPacket() { @@ -30,19 +40,8 @@ bool VoxelPacket::append(const unsigned char* data, int length) { memcpy(&_uncompressed[_bytesInUse], data, length); _bytesInUse += length; _bytesAvailable -= length; - success = true; - - /**** - // Now, check for compression, if we fit, then proceed, otherwise, rollback. - if (checkCompress()) { - success = true; - } else { - // rollback is easy, we just reset _bytesInUse and _bytesAvailable - _bytesInUse -= length; - _bytesAvailable += length; - } - ***/ + _dirty = true; } return success; } @@ -53,19 +52,8 @@ bool VoxelPacket::append(unsigned char byte) { _uncompressed[_bytesInUse] = byte; _bytesInUse++; _bytesAvailable--; - success = true; - - /**** - // Now, check for compression, if we fit, then proceed, otherwise, rollback. - if (checkCompress()) { - success = true; - } else { - // rollback is easy, we just reset _bytesInUse and _bytesAvailable - _bytesInUse--; - _bytesAvailable++; - } - ****/ + _dirty = true; } return success; } @@ -73,20 +61,9 @@ bool VoxelPacket::append(unsigned char byte) { bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { - unsigned char oldValue = _uncompressed[offset]; _uncompressed[offset] = bitmask; - success = true; - - /**** - // Now, check for compression, if we fit, then proceed, otherwise, rollback. - if (checkCompress()) { - success = true; - } else { - // rollback is easy, the length didn't change, but we need to restore the previous value - _uncompressed[offset] = oldValue; - } - ****/ + _dirty = true; } return success; } @@ -94,21 +71,9 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) { bool success = false; if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { - unsigned char oldValues[length]; - memcpy(&oldValues[0], &_uncompressed[offset], length); // save the old values for restore memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content - success = true; - - /**** - // Now, check for compression, if we fit, then proceed, otherwise, rollback. - if (checkCompress()) { - success = true; - } else { - // rollback is easy, the length didn't change, but we need to restore the previous values - memcpy(&_uncompressed[offset], &oldValues[0], length); // restore the old values - } - ****/ + _dirty = true; } return success; } @@ -130,6 +95,33 @@ bool VoxelPacket::startSubTree(const unsigned char* octcode) { return success; } +const unsigned char* VoxelPacket::getFinalizedData() { + if (!_enableCompression) { + return &_uncompressed[0]; + } + + if (_dirty) { +if (_debug) printf("getFinalizedData() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + checkCompress(); + } + + return &_compressed[0]; +} + +int VoxelPacket::getFinalizedSize() { + if (!_enableCompression) { + return _bytesInUse; + } + + if (_dirty) { +if (_debug) printf("getFinalizedSize() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + checkCompress(); + } + + return _compressedBytes; +} + + void VoxelPacket::endSubTree() { _subTreeAt = _bytesInUse; } @@ -139,11 +131,7 @@ void VoxelPacket::discardSubTree() { _bytesInUse -= bytesInSubTree; _bytesAvailable += bytesInSubTree; _subTreeAt = _bytesInUse; // should be the same actually... - - // we can be confident that it will compress, because we can't get here without previously being able to compress - // the content up to this point in the uncompressed buffer. But we still call this because it cleans up the compressed - // buffer with the correct content - checkCompress(); + _dirty = true; } int VoxelPacket::startLevel() { @@ -153,17 +141,28 @@ int VoxelPacket::startLevel() { void VoxelPacket::discardLevel(int key) { int bytesInLevel = _bytesInUse - key; + +if (_debug) printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", + debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse); + _bytesInUse -= bytesInLevel; _bytesAvailable += bytesInLevel; + _dirty = true; - // we can be confident that it will compress, because we can't get here without previously being able to compress - // the content up to this point in the uncompressed buffer. But we still call this because it cleans up the compressed - // buffer with the correct content - checkCompress(); +if (_debug) printf("discardLevel() AFTER _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", + debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse); } bool VoxelPacket::endLevel(int key) { - bool success = checkCompress(); + bool success = true; + + // if we've never compressed, then compress to see our size + // or, if we're within 50% of our MAX_VOXEL_PACKET_SIZE then check... + // otherwise assume it's safe... + if (_dirty && (_compressedBytes == 0 || _bytesInUse > COMPRESSION_TEST_THRESHOLD)) { +if (_debug) printf("endLevel() _dirty=%s _compressedBytes=%d _bytesInUse=%d\n",debug::valueOf(_dirty), _compressedBytes, _bytesInUse); + success = checkCompress(); + } if (!success) { discardLevel(key); } @@ -196,22 +195,24 @@ uint64_t VoxelPacket::_checkCompressCalls = 0; bool VoxelPacket::checkCompress() { PerformanceWarning warn(false,"VoxelPacket::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls); + + // without compression, we always pass... + if (!_enableCompression) { + return true; + } bool success = false; - const int MAX_COMPRESSION = 9; + const int MAX_COMPRESSION = 2; // we only want to compress the data payload, not the message header - QByteArray compressedData = qCompress(_uncompressed,_bytesInUse, MAX_COMPRESSION); + QByteArray compressedData = qCompress(_uncompressed, _bytesInUse, MAX_COMPRESSION); if (compressedData.size() < MAX_VOXEL_PACKET_SIZE) { - //memcpy(&_compressed[0], compressedData.constData(), compressedData.size()); - _compressedBytes = compressedData.size(); for (int i = 0; i < _compressedBytes; i++) { _compressed[i] = compressedData[i]; } - -//printf("compressed %d bytes from %d original bytes\n", _compressedBytes, _bytesInUse); + _dirty = false; success = true; } return success; @@ -220,28 +221,35 @@ bool VoxelPacket::checkCompress() { void VoxelPacket::loadCompressedContent(const unsigned char* data, int length) { reset(); // by definition we reset upon loading compressed content - - if (length > 0) { - QByteArray compressedData; - - for (int i = 0; i < length; i++) { - compressedData[i] = data[i]; - _compressed[i] = compressedData[i]; - } - _compressedBytes = length; - QByteArray uncompressedData = qUncompress(compressedData); + if (length > 0) { + if (_enableCompression) { + QByteArray compressedData; - if (uncompressedData.size() <= _bytesAvailable) { - _bytesInUse = uncompressedData.size(); - _bytesAvailable -= uncompressedData.size(); - - for (int i = 0; i < _bytesInUse; i++) { - _uncompressed[i] = uncompressedData[i]; + for (int i = 0; i < length; i++) { + compressedData[i] = data[i]; + _compressed[i] = compressedData[i]; } + _compressedBytes = length; + + QByteArray uncompressedData = qUncompress(compressedData); + + if (uncompressedData.size() <= _bytesAvailable) { + _bytesInUse = uncompressedData.size(); + _bytesAvailable -= uncompressedData.size(); + + for (int i = 0; i < _bytesInUse; i++) { + _uncompressed[i] = uncompressedData[i]; + } + } + } else { + for (int i = 0; i < length; i++) { + _uncompressed[i] = _compressed[i] = data[i]; + } + _bytesInUse = _compressedBytes = length; } } else { - printf("VoxelPacket::loadCompressedContent()... length = 0, nothing to do...\n"); + if (_debug) printf("VoxelPacket::loadCompressedContent()... length = 0, nothing to do...\n"); } } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 037b49e9ba..244b60a750 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -6,8 +6,11 @@ // // TO DO: // +// * add support to "disable" compression (fix SAVE!) +// +// * improve compression to be less expensive (mostly determine when to test compression...) +// // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. -// * add compression // * improve semantics for "reshuffle" - current approach will work for now and with compression // but wouldn't work with RLE because the colors in the levels would get reordered and RLE would need // to be recalculated @@ -24,7 +27,7 @@ class VoxelPacket { public: - VoxelPacket(); + VoxelPacket(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_SIZE); ~VoxelPacket(); /// reset completely, all data is discarded @@ -69,9 +72,9 @@ public: int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } /// get access to the finalized data (it may be compressed or rewritten into optimal form) - const unsigned char* getFinalizedData() { return &_compressed[0]; } + const unsigned char* getFinalizedData(); /// get size of the finalized data (it may be compressed or rewritten into optimal form) - int getFinalizedSize() const { return _compressedBytes; } + int getFinalizedSize(); /// get pointer to the start of uncompressed stream buffer const unsigned char* getUncompressedData() { return &_uncompressed[0]; } @@ -96,6 +99,9 @@ private: /// append a single byte, might fail if byte would cause packet to be too large bool append(unsigned char byte); + bool _enableCompression; + int _maxFinalizedSize; + unsigned char _uncompressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; int _bytesAvailable; @@ -103,10 +109,11 @@ private: bool checkCompress(); - unsigned char _compressed[MAX_VOXEL_PACKET_SIZE]; + unsigned char _compressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _compressedBytes; + bool _dirty; - + static bool _debug; }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file From 57633f8b922980592d455aa9ac254b1eba0329fc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 00:05:06 -0800 Subject: [PATCH 44/77] fixed comment --- libraries/voxels/src/VoxelPacket.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 244b60a750..4930f7f51f 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -6,8 +6,6 @@ // // TO DO: // -// * add support to "disable" compression (fix SAVE!) -// // * improve compression to be less expensive (mostly determine when to test compression...) // // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. From e2f5069e6a7de944453ca9f0b96eb58bb5fb2abd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 14:41:50 -0800 Subject: [PATCH 45/77] more VoxelPacket compression tuning --- interface/src/VoxelSystem.cpp | 4 +-- .../src/VoxelSendThread.cpp | 25 +++++++++------- libraries/voxels/src/VoxelConstants.h | 8 +++-- libraries/voxels/src/VoxelPacket.cpp | 30 ++++++++++++++----- libraries/voxels/src/VoxelPacket.h | 1 + 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 21e7809014..622247df8a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -597,7 +597,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); - VoxelPacket packet; + VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); int compressedSize = numBytes - numBytesPacketHeader; packet.loadCompressedContent(voxelData, compressedSize); printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); @@ -611,7 +611,7 @@ printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numByt // ask the VoxelTree to read the MONOCHROME bitstream into the tree ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); - VoxelPacket packet; + VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); int compressedSize = numBytes - numBytesPacketHeader; packet.loadCompressedContent(voxelData, compressedSize); printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 5d96cedb5d..4137ad67cc 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -21,7 +21,9 @@ extern EnvironmentData environmentData[3]; VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : _nodeUUID(nodeUUID), _myServer(myServer), - _encodedSomething(false) { + _tempPacket(VOXEL_PACKET_COMPRESSION_DEFAULT), + _encodedSomething(false) +{ } bool VoxelSendThread::process() { @@ -422,22 +424,25 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start)/1000; + + uint64_t endCompressCalls = VoxelPacket::_checkCompressCalls; + int elapsedCompressCalls = endCompressCalls - startCompressCalls; + + uint64_t endCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; + int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; + + if (elapsedmsec > 100) { if (elapsedmsec > 1000) { int elapsedsec = (end - start)/1000000; - printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets %d nodes still to send\n", - elapsedsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + printf("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets %d nodes still to send\n", + elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } else { - printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", - elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + printf("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", + elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } } else if (truePacketsSent > 0 /*_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()*/) { - uint64_t endCompressCalls = VoxelPacket::_checkCompressCalls; - int elapsedCompressCalls = endCompressCalls - startCompressCalls; - - uint64_t endCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; - int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index e53107f80e..7fcbd6e308 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -35,9 +35,11 @@ const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); -const int MAX_VOXEL_PACKET_COMPRESSION_RATIO = 3; -const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 3000; // MAX_VOXEL_PACKET_SIZE * MAX_VOXEL_PACKET_COMPRESSION_RATIO; -const int COMPRESSION_TEST_THRESHOLD = 2000; +const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500; +const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400; +const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; +const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; +const int VOXEL_PACKET_COMPRESSION_DEFAULT = true; const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 9911055d3c..9d0d062c1f 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -27,6 +27,7 @@ void VoxelPacket::reset() { } _subTreeAt = 0; _compressedBytes = 0; + _bytesInUseLastCheck = 0; _dirty = false; } @@ -101,7 +102,9 @@ const unsigned char* VoxelPacket::getFinalizedData() { } if (_dirty) { -if (_debug) printf("getFinalizedData() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + if (_debug) { + printf("getFinalizedData() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + } checkCompress(); } @@ -114,7 +117,9 @@ int VoxelPacket::getFinalizedSize() { } if (_dirty) { -if (_debug) printf("getFinalizedSize() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + if (_debug) { + printf("getFinalizedSize() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); + } checkCompress(); } @@ -156,11 +161,21 @@ if (_debug) printf("discardLevel() AFTER _dirty=%s bytesInLevel=%d _compressedBy bool VoxelPacket::endLevel(int key) { bool success = true; - // if we've never compressed, then compress to see our size - // or, if we're within 50% of our MAX_VOXEL_PACKET_SIZE then check... - // otherwise assume it's safe... - if (_dirty && (_compressedBytes == 0 || _bytesInUse > COMPRESSION_TEST_THRESHOLD)) { -if (_debug) printf("endLevel() _dirty=%s _compressedBytes=%d _bytesInUse=%d\n",debug::valueOf(_dirty), _compressedBytes, _bytesInUse); + // if we are dirty (something has changed) then try a compression test in the following cases... + // 1) If we've previously compressed and our _compressedBytes are "close enough to our limit" that we want to keep + // testing to make sure we don't overflow... VOXEL_PACKET_ALWAYS_TEST_COMPRESSION_THRESHOLD + // 2) If we've passed the uncompressed size where we believe we might pass the compressed threshold, and we've added + // a sufficient number of uncompressed bytes + if (_dirty && ( + (_compressedBytes > VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD) || + ( (_bytesInUse > VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD) && + (_bytesInUse - _bytesInUseLastCheck > VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD) + ) + )) { + if (_debug) { + printf("endLevel() _dirty=%s _compressedBytes=%d _bytesInUse=%d\n", + debug::valueOf(_dirty), _compressedBytes, _bytesInUse); + } success = checkCompress(); } if (!success) { @@ -201,6 +216,7 @@ bool VoxelPacket::checkCompress() { return true; } + _bytesInUseLastCheck = _bytesInUse; bool success = false; const int MAX_COMPRESSION = 2; diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 4930f7f51f..2122467af1 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -109,6 +109,7 @@ private: unsigned char _compressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _compressedBytes; + int _bytesInUseLastCheck; bool _dirty; static bool _debug; From 94584d4ead461fee818c0272019b65a275a99b99 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 15:01:37 -0800 Subject: [PATCH 46/77] disable voxel packet compression for now --- libraries/voxels/src/VoxelConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 7fcbd6e308..1ba1f10cc1 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -39,7 +39,7 @@ const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500; const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400; const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; -const int VOXEL_PACKET_COMPRESSION_DEFAULT = true; +const int VOXEL_PACKET_COMPRESSION_DEFAULT = false; const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; From 25511f99ec656883f2744ce2d73823e8d94ff34b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 15:22:44 -0800 Subject: [PATCH 47/77] cleanup for coding standard --- interface/src/VoxelSystem.cpp | 12 ++++++++---- libraries/shared/src/OctalCode.cpp | 4 ++-- libraries/shared/src/SharedUtil.cpp | 10 +++++----- .../voxel-server-library/src/VoxelSendThread.cpp | 13 ++++--------- libraries/voxels/src/VoxelPacket.cpp | 10 +++++++--- libraries/voxels/src/VoxelPacket.h | 7 ++++--- 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 622247df8a..92abf43061 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -599,8 +599,10 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { lockTree(); VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); int compressedSize = numBytes - numBytesPacketHeader; - packet.loadCompressedContent(voxelData, compressedSize); -printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + packet.loadFinalizedContent(voxelData, compressedSize); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + } _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); unlockTree(); } @@ -613,8 +615,10 @@ printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numByt lockTree(); VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); int compressedSize = numBytes - numBytesPacketHeader; - packet.loadCompressedContent(voxelData, compressedSize); -printf("got packet numBytes=%d compressed size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + packet.loadFinalizedContent(voxelData, compressedSize); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + } _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); unlockTree(); } diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 5f79a7dfa5..027a6a4d68 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -32,12 +32,12 @@ int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) void printOctalCode(const unsigned char* octalCode) { if (!octalCode) { - printf("NULL\n"); + qDebug("NULL\n"); } else { for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { outputBits(octalCode[i],false); } - printf("\n"); + qDebug("\n"); } } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index b9d5f9da60..8c56c250e0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -71,18 +71,18 @@ void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - printf("[ %d (%c): ", byte, byte); + qDebug("[ %d (%c): ", byte, byte); } else { - printf("[ %d (0x%x): ", byte, byte); + qDebug("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - printf("%d", byte >> (7 - i) & 1); + qDebug("%d", byte >> (7 - i) & 1); } - printf(" ] "); + qDebug(" ] "); if (withNewLine) { - printf("\n"); + qDebug("\n"); } } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 4137ad67cc..6c51156490 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -374,15 +374,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - - //printf("calling nodeBag.count()=%d encode()... subTree=%p \n", nodeData->nodeBag.count(), subTree); - //printOctalCode(subTree->getOctalCode()); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); - - - //printf("called encode()... bytesWritten=%d compressedSize=%d uncompressedSize=%d\n",bytesWritten, _tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); - if (bytesWritten > 0) { _encodedSomething = true; } @@ -399,7 +391,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // mean we should send the previous packet contents and reset it. bool sendNow = (bytesWritten == 0); if (_tempPacket.hasContent() && sendNow) { - //printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",_tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", + _tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); + } nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); _tempPacket.reset(); diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index 9d0d062c1f..bbd53e070c 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -147,15 +147,19 @@ int VoxelPacket::startLevel() { void VoxelPacket::discardLevel(int key) { int bytesInLevel = _bytesInUse - key; -if (_debug) printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", + if (_debug) { + printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse); + } _bytesInUse -= bytesInLevel; _bytesAvailable += bytesInLevel; _dirty = true; -if (_debug) printf("discardLevel() AFTER _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", + if (_debug) { + printf("discardLevel() AFTER _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse); + } } bool VoxelPacket::endLevel(int key) { @@ -235,7 +239,7 @@ bool VoxelPacket::checkCompress() { } -void VoxelPacket::loadCompressedContent(const unsigned char* data, int length) { +void VoxelPacket::loadFinalizedContent(const unsigned char* data, int length) { reset(); // by definition we reset upon loading compressed content if (length > 0) { diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 2122467af1..0791907971 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -6,9 +6,10 @@ // // TO DO: // -// * improve compression to be less expensive (mostly determine when to test compression...) +// * further testing of compression to determine optimal configuration for performance and compression // // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. +// // * improve semantics for "reshuffle" - current approach will work for now and with compression // but wouldn't work with RLE because the colors in the levels would get reordered and RLE would need // to be recalculated @@ -82,8 +83,8 @@ public: /// has some content been written to the packet bool hasContent() const { return (_bytesInUse > 0); } - /// load compressed content to allow access to decoded content for parsing - void loadCompressedContent(const unsigned char* data, int length); + /// load finalized content to allow access to decoded content for parsing + void loadFinalizedContent(const unsigned char* data, int length); void debugContent(); From 3ef7c1a7322a3f79b6a908ef3a4c87098c51b0fd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 15:28:50 -0800 Subject: [PATCH 48/77] moved const definitions to better file --- libraries/voxel-server-library/src/VoxelNodeData.h | 1 + libraries/voxels/src/VoxelConstants.h | 6 ------ libraries/voxels/src/VoxelPacket.h | 7 ++++++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 373a6e0886..081844ac08 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 1ba1f10cc1..3a66f6f564 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -34,12 +34,6 @@ const float DEFAULT_VOXEL_SIZE_SCALE = TREE_SCALE * 400.0f; const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; -const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); -const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500; -const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400; -const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; -const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; -const int VOXEL_PACKET_COMPRESSION_DEFAULT = false; const int MAX_TREE_SLICE_BYTES = 26; const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 0791907971..f083a0f657 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -22,7 +22,12 @@ #include "VoxelConstants.h" #include "VoxelNode.h" - +const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); +const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500; +const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400; +const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; +const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; +const int VOXEL_PACKET_COMPRESSION_DEFAULT = false; class VoxelPacket { public: From 32e770d2b763c4678e8cc50f47e17c45300c773d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 16:02:05 -0800 Subject: [PATCH 49/77] tweaks to debugging --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 6c51156490..82fc8a8d05 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -86,7 +86,7 @@ uint64_t VoxelSendThread::_totalWastedBytes = 0; uint64_t VoxelSendThread::_totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = _myServer->wantsDebugVoxelSending(); + bool debug = true; // _myServer->wantsDebugVoxelSending(); bool packetSent = false; // did we send a packet? int packetsSent = 0; @@ -436,7 +436,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod printf("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (truePacketsSent > 0 /*_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()*/) { + } else if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); From 0cd269632e3bd9ea5e4bc4bd8bbd31d307fd5a45 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 17:49:10 -0800 Subject: [PATCH 50/77] fix bug where some parts of scene weren't sent, turned out it was in the octal code not fitting voxels getting ignored --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 7 +++++++ libraries/voxels/src/VoxelPacket.h | 8 ++++++-- libraries/voxels/src/VoxelTree.cpp | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 82fc8a8d05..980108eddb 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -375,6 +375,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); + + if (_tempPacket.hasContent() && bytesWritten == 0 && _tempPacket.getFinalizedSize() < 1450) { + printf(">>>>>>>>>>>>>>> got bytesWritten==0 _tempPacket.getFinalizedSize()=%d <<<<<<<<<<<<<<<\n", + _tempPacket.getFinalizedSize()); + + } + if (bytesWritten > 0) { _encodedSomething = true; } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index f083a0f657..a636e8aae3 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -6,10 +6,14 @@ // // TO DO: // -// * further testing of compression to determine optimal configuration for performance and compression -// // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. // +// * determine why we sometimes don't fill packets very well (rarely) mid-scene... sometimes it appears as if +// the "next node" would encode with more bytes than can fit in the remainder of the packet. this might be +// several tens or hundreds of bytes, but theoretically other voxels would have fit. This happens in the 0100 +// scene a couple times. +// +// * further testing of compression to determine optimal configuration for performance and compression // * improve semantics for "reshuffle" - current approach will work for now and with compression // but wouldn't work with RLE because the colors in the levels would get reordered and RLE would need // to be recalculated diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8ef2cd7d66..6cbc25880b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1062,6 +1062,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { doneEncoding(node); + bag.insert(node); // add the node back to the bag so it will eventually get included return bytesWritten; } From ed80895eb3d6b992c9873e8be72df38bdefc2b7d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 20:29:54 -0800 Subject: [PATCH 51/77] fix issue where we sometimes don't completely fill a packet mid scene --- .../src/VoxelSendThread.cpp | 11 +++--- libraries/voxels/src/VoxelPacket.h | 7 +++- libraries/voxels/src/VoxelTree.cpp | 16 ++++++++- libraries/voxels/src/VoxelTree.h | 36 ++++++++++++++++++- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 980108eddb..e4f6c10856 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -350,6 +350,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod break; } + bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { VoxelNode* subTree = nodeData->nodeBag.extract(); bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); @@ -375,11 +376,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); - - if (_tempPacket.hasContent() && bytesWritten == 0 && _tempPacket.getFinalizedSize() < 1450) { - printf(">>>>>>>>>>>>>>> got bytesWritten==0 _tempPacket.getFinalizedSize()=%d <<<<<<<<<<<<<<<\n", - _tempPacket.getFinalizedSize()); - + + if (_tempPacket.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { + lastNodeDidntFit = true; } if (bytesWritten > 0) { @@ -396,7 +395,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // We only consider sending anything if there is something in the _tempPacket to send... But // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. - bool sendNow = (bytesWritten == 0); + bool sendNow = lastNodeDidntFit; if (_tempPacket.hasContent() && sendNow) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index a636e8aae3..6c5a3aebd5 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -11,7 +11,12 @@ // * determine why we sometimes don't fill packets very well (rarely) mid-scene... sometimes it appears as if // the "next node" would encode with more bytes than can fit in the remainder of the packet. this might be // several tens or hundreds of bytes, but theoretically other voxels would have fit. This happens in the 0100 -// scene a couple times. +// scene a couple times. +// this is happening because of nodes that are not recursed for good reason like: +// - being occluded +// - being previously in view +// - being out of view, etc. +// in these cases, the node is not re-added to the bag... so, we can probably just keep going... // // * further testing of compression to determine optimal configuration for performance and compression // * improve semantics for "reshuffle" - current approach will work for now and with compression diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6cbc25880b..f923c9ca5b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1031,6 +1031,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // you can't call this without a valid node if (!node) { qDebug("WARNING! encodeTreeBitstream() called with node=NULL\n"); + params.stopReason = EncodeBitstreamParams::NULL_NODE; return bytesWritten; } @@ -1039,6 +1040,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { doneEncoding(node); + params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesWritten; } @@ -1063,6 +1065,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, if (!roomForOctalCode) { doneEncoding(node); bag.insert(node); // add the node back to the bag so it will eventually get included + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; return bytesWritten; } @@ -1085,6 +1088,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, // couldn't be written... so reset them here... This isn't true for the non-color included case if (params.includeColor && childBytesWritten == 2) { childBytesWritten = 0; + //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } // if we wrote child bytes, then return our result of all bytes written @@ -1093,6 +1097,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } else { // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code bytesWritten = 0; + //params.stopReason = EncodeBitstreamParams::DIDNT_FIT; } if (bytesWritten == 0) { @@ -1115,6 +1120,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // you can't call this without a valid node if (!node) { qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL\n"); + params.stopReason = EncodeBitstreamParams::NULL_NODE; return bytesAtThisLevel; } @@ -1125,6 +1131,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // If we've reached our max Search Level, then stop searching. if (currentEncodeLevel >= params.maxEncodeLevel) { + params.stopReason = EncodeBitstreamParams::TOO_DEEP; return bytesAtThisLevel; } @@ -1133,6 +1140,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // here's how it works... if we're currently above our root jurisdiction, then we proceed normally. // but once we're in our own jurisdiction, then we need to make sure we're not below it. if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), CHECK_NODE_ONLY)) { + params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION; return bytesAtThisLevel; } } @@ -1148,6 +1156,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.stats) { params.stats->skippedDistance(node); } + params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } @@ -1158,6 +1167,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.stats) { params.stats->skippedOutOfView(node); } + params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesAtThisLevel; } @@ -1197,6 +1207,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.stats) { params.stats->skippedWasInView(node); } + params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW; return bytesAtThisLevel; } @@ -1207,6 +1218,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.stats) { params.stats->skippedNoChange(node); } + params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } @@ -1226,6 +1238,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (params.stats) { params.stats->skippedOccluded(node); } + params.stopReason = EncodeBitstreamParams::OCCLUDED; return bytesAtThisLevel; } } else { @@ -1616,7 +1629,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, params.stats->didntFit(node); } - return 0; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + bytesAtThisLevel = 0; // didn't fit } return bytesAtThisLevel; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 48c001a3d0..29bfba28f9 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -66,6 +66,21 @@ public: CoverageMap* map; JurisdictionMap* jurisdictionMap; + // output hints from the encode process + typedef enum { + UNKNOWN, + DIDNT_FIT, + NULL_NODE, + TOO_DEEP, + OUT_OF_JURISDICTION, + LOD_SKIP, + OUT_OF_VIEW, + WAS_IN_VIEW, + NO_CHANGE, + OCCLUDED + } reason; + reason stopReason; + EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, @@ -97,8 +112,27 @@ public: forceSendScene(forceSendScene), stats(stats), map(map), - jurisdictionMap(jurisdictionMap) + jurisdictionMap(jurisdictionMap), + stopReason(UNKNOWN) {} + + void displayStopReason() { + printf("StopReason: "); + switch (stopReason) { + default: + case UNKNOWN: printf("UNKNOWN\n"); break; + + case DIDNT_FIT: printf("DIDNT_FIT\n"); break; + case NULL_NODE: printf("NULL_NODE\n"); break; + case TOO_DEEP: printf("TOO_DEEP\n"); break; + case OUT_OF_JURISDICTION: printf("OUT_OF_JURISDICTION\n"); break; + case LOD_SKIP: printf("LOD_SKIP\n"); break; + case OUT_OF_VIEW: printf("OUT_OF_VIEW\n"); break; + case WAS_IN_VIEW: printf("WAS_IN_VIEW\n"); break; + case NO_CHANGE: printf("NO_CHANGE\n"); break; + case OCCLUDED: printf("OCCLUDED\n"); break; + } + } }; class ReadBitstreamToTreeParams { From 8d8d73a940317c5706923a79c5a39a59af1f8f7f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 20:49:47 -0800 Subject: [PATCH 52/77] start of statistics, convert level key into class --- libraries/voxels/src/VoxelPacket.cpp | 30 ++++++++++++++----- libraries/voxels/src/VoxelPacket.h | 43 +++++++++++++++++++--------- libraries/voxels/src/VoxelTree.cpp | 2 +- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index bbd53e070c..bd7ec7230c 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -10,6 +10,10 @@ #include "VoxelPacket.h" bool VoxelPacket::_debug = false; +uint64_t VoxelPacket::_bytesOfOctalCodes = 0; +uint64_t VoxelPacket::_bytesOfBitMasks = 0; +uint64_t VoxelPacket::_bytesOfColor = 0; + VoxelPacket::VoxelPacket(bool enableCompression, int maxFinalizedSize) { @@ -82,17 +86,22 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB bool VoxelPacket::startSubTree(const unsigned char* octcode) { bool success = false; int possibleStartAt = _bytesInUse; + int length = 0; if (octcode) { - int length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode)); + length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode)); success = append(octcode, length); // handles checking compression } else { // NULL case, means root node, which is 0 unsigned char byte = 0; + length = 1; success = append(byte); // handles checking compression } if (success) { _subTreeAt = possibleStartAt; } + if (success) { + _bytesOfOctalCodes += length; + } return success; } @@ -139,13 +148,13 @@ void VoxelPacket::discardSubTree() { _dirty = true; } -int VoxelPacket::startLevel() { - int key = _bytesInUse; +LevelDetails VoxelPacket::startLevel() { + LevelDetails key(_bytesInUse,0,0,0); return key; } -void VoxelPacket::discardLevel(int key) { - int bytesInLevel = _bytesInUse - key; +void VoxelPacket::discardLevel(LevelDetails key) { + int bytesInLevel = _bytesInUse - key._startIndex; if (_debug) { printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", @@ -162,7 +171,7 @@ void VoxelPacket::discardLevel(int key) { } } -bool VoxelPacket::endLevel(int key) { +bool VoxelPacket::endLevel(LevelDetails key) { bool success = true; // if we are dirty (something has changed) then try a compression test in the following cases... @@ -189,7 +198,11 @@ bool VoxelPacket::endLevel(int key) { } bool VoxelPacket::appendBitMask(unsigned char bitmask) { - return append(bitmask); // handles checking compression + bool success = append(bitmask); // handles checking compression + if (success) { + _bytesOfBitMasks++; + } + return success; } bool VoxelPacket::appendColor(const nodeColor& color) { @@ -206,6 +219,9 @@ bool VoxelPacket::appendColor(const nodeColor& color) { } } } + if (success) { + _bytesOfColor += BYTES_PER_COLOR; + } return success; } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 6c5a3aebd5..bb8b8bbb02 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -7,16 +7,8 @@ // TO DO: // // * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. -// -// * determine why we sometimes don't fill packets very well (rarely) mid-scene... sometimes it appears as if -// the "next node" would encode with more bytes than can fit in the remainder of the packet. this might be -// several tens or hundreds of bytes, but theoretically other voxels would have fit. This happens in the 0100 -// scene a couple times. -// this is happening because of nodes that are not recursed for good reason like: -// - being occluded -// - being previously in view -// - being out of view, etc. -// in these cases, the node is not re-added to the bag... so, we can probably just keep going... +// - this is challenging, because you need to support the rollback of statistics when +// you discard a level or discard // // * further testing of compression to determine optimal configuration for performance and compression // * improve semantics for "reshuffle" - current approach will work for now and with compression @@ -38,6 +30,23 @@ const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; const int VOXEL_PACKET_COMPRESSION_DEFAULT = false; +class LevelDetails { + LevelDetails(int startIndex, int bytesOfOctalCodes, int bytesOfBitmasks, int bytesOfColor) : + _startIndex(startIndex), + _bytesOfOctalCodes(bytesOfOctalCodes), + _bytesOfBitmasks(bytesOfBitmasks), + _bytesOfColor(bytesOfColor) { + } + + friend class VoxelPacket; + +private: + int _startIndex; + int _bytesOfOctalCodes; + int _bytesOfBitmasks; + int _bytesOfColor; +}; + class VoxelPacket { public: VoxelPacket(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_SIZE); @@ -57,14 +66,14 @@ public: void discardSubTree(); /// starts a level marker. returns an opaque key which can be used to discard the level - int startLevel(); + LevelDetails startLevel(); /// discards all content back to a previous marker key - void discardLevel(int key); + void discardLevel(LevelDetails key); /// ends a level, and performs any expensive finalization. may fail if finalization creates a stream which is too large /// if the finalization would fail, the packet will automatically discard the previous level. - bool endLevel(int key); + bool endLevel(LevelDetails key); /// appends a bitmask to the end of the stream, may fail if new data stream is too long to fit in packet bool appendBitMask(unsigned char bitmask); @@ -126,8 +135,14 @@ private: int _compressedBytes; int _bytesInUseLastCheck; bool _dirty; - + + // statistics... + static uint64_t _bytesOfOctalCodes; + static uint64_t _bytesOfBitMasks; + static uint64_t _bytesOfColor; + static bool _debug; + }; #endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index f923c9ca5b..06bdc12f02 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1261,7 +1261,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const int BYTES_PER_COLOR = 3; // Make our local buffer large enough to handle writing at this level in case we need to. - int thisLevelKey = packet->startLevel(); + LevelDetails thisLevelKey = packet->startLevel(); int inViewCount = 0; int inViewNotLeafCount = 0; From 8bb2bd2ecfd9f5eae727e5484c9daa2ba3a9fbd4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 00:26:37 -0800 Subject: [PATCH 53/77] get voxel packet statistics to work and add them to server status page --- .../src/VoxelSendThread.cpp | 8 +++-- .../src/VoxelSendThread.h | 9 ++--- .../voxel-server-library/src/VoxelServer.cpp | 31 +++++++++++++++- libraries/voxels/src/VoxelPacket.cpp | 35 ++++++++++++++++--- libraries/voxels/src/VoxelPacket.h | 13 ++++--- 5 files changed, 81 insertions(+), 15 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index e4f6c10856..f01b300cef 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -111,7 +111,9 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); statsMessageLength += nodeData->getPacketLength(); - int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength at this point includes data + // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since + // there was nothing else to send. + int thisWastedBytes = 0; _totalWastedBytes += thisWastedBytes; _totalBytes += nodeData->getPacketLength(); _totalPackets++; @@ -129,7 +131,9 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // not enough room in the packet, send two packets NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); - int thisWastedBytes = MAX_PACKET_SIZE - statsMessageLength; // the statsMessageLength is only the stats + // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since + // there was nothing else to send. + int thisWastedBytes = 0; _totalWastedBytes += thisWastedBytes; _totalBytes += nodeData->getPacketLength(); _totalPackets++; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 607e1a9e0d..f088163f4d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -22,6 +22,11 @@ class VoxelSendThread : public virtual GenericThread { public: VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer); + + static uint64_t _totalBytes; + static uint64_t _totalWastedBytes; + static uint64_t _totalPackets; + protected: /// Implements generic processing behavior for this thread. virtual bool process(); @@ -37,10 +42,6 @@ private: VoxelPacket _tempPacket; bool _encodedSomething; - static uint64_t _totalBytes; - static uint64_t _totalWastedBytes; - static uint64_t _totalPackets; - }; #endif // __voxel_server__VoxelSendThread__ diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index cf650117f2..36db9ee1ca 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -262,6 +262,36 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "\r\n"); + + // display outbound packet stats + mg_printf(connection, "%s", "Voxel Packet Statistics...\r\n"); + uint64_t totalOutboundPackets = VoxelSendThread::_totalPackets; + uint64_t totalOutboundBytes = VoxelSendThread::_totalBytes; + uint64_t totalWastedBytes = VoxelSendThread::_totalWastedBytes; + uint64_t totalBytesOfOctalCodes = VoxelPacket::_totalBytesOfOctalCodes; + uint64_t totalBytesOfBitMasks = VoxelPacket::_totalBytesOfBitMasks; + uint64_t totalBytesOfColor = VoxelPacket::_totalBytesOfColor; + + const int COLUMN_WIDTH = 10; + mg_printf(connection, " Total Outbound Packets: %s packets\r\n", + locale.toString((uint)totalOutboundPackets).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData()); + mg_printf(connection, " Total Outbound Bytes: %s bytes\r\n", + locale.toString((uint)totalOutboundBytes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData()); + mg_printf(connection, " Total Wasted Bytes: %s bytes\r\n", + locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData()); + mg_printf(connection, " Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n", + locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), + ((float)totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT); + mg_printf(connection, " Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n", + locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), + ((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT); + mg_printf(connection, " Total Color Bytes: %s bytes (%5.2f%%)\r\n", + locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), + ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT); + + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "\r\n"); + // display inbound packet stats mg_printf(connection, "%s", "Voxel Edit Statistics... [RESET]\r\n"); uint64_t averageTransitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageTransitTimePerPacket(); @@ -274,7 +304,6 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { float averageVoxelsPerPacket = totalPacketsProcessed == 0 ? 0 : totalVoxelsProcessed / totalPacketsProcessed; - const int COLUMN_WIDTH = 10; mg_printf(connection, " Total Inbound Packets: %s packets\r\n", locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData()); mg_printf(connection, " Total Inbound Voxels: %s voxels\r\n", diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacket.cpp index bd7ec7230c..f0d2c97ace 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacket.cpp @@ -10,9 +10,9 @@ #include "VoxelPacket.h" bool VoxelPacket::_debug = false; -uint64_t VoxelPacket::_bytesOfOctalCodes = 0; -uint64_t VoxelPacket::_bytesOfBitMasks = 0; -uint64_t VoxelPacket::_bytesOfColor = 0; +uint64_t VoxelPacket::_totalBytesOfOctalCodes = 0; +uint64_t VoxelPacket::_totalBytesOfBitMasks = 0; +uint64_t VoxelPacket::_totalBytesOfColor = 0; @@ -33,6 +33,11 @@ void VoxelPacket::reset() { _compressedBytes = 0; _bytesInUseLastCheck = 0; _dirty = false; + + _bytesOfOctalCodes = 0; + _bytesOfBitMasks = 0; + _bytesOfColor = 0; + _bytesOfOctalCodesCurrentSubTree = 0; } VoxelPacket::~VoxelPacket() { @@ -84,6 +89,7 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB } bool VoxelPacket::startSubTree(const unsigned char* octcode) { + _bytesOfOctalCodesCurrentSubTree = _bytesOfOctalCodes; bool success = false; int possibleStartAt = _bytesInUse; int length = 0; @@ -101,6 +107,7 @@ bool VoxelPacket::startSubTree(const unsigned char* octcode) { } if (success) { _bytesOfOctalCodes += length; + _totalBytesOfOctalCodes += length; } return success; } @@ -146,15 +153,33 @@ void VoxelPacket::discardSubTree() { _bytesAvailable += bytesInSubTree; _subTreeAt = _bytesInUse; // should be the same actually... _dirty = true; + + // rewind to start of this subtree, other items rewound by endLevel() + int reduceBytesOfOctalCodes = _bytesOfOctalCodes - _bytesOfOctalCodesCurrentSubTree; + _bytesOfOctalCodes = _bytesOfOctalCodesCurrentSubTree; + _totalBytesOfOctalCodes -= reduceBytesOfOctalCodes; } LevelDetails VoxelPacket::startLevel() { - LevelDetails key(_bytesInUse,0,0,0); + LevelDetails key(_bytesInUse, _bytesOfOctalCodes, _bytesOfBitMasks, _bytesOfColor); return key; } void VoxelPacket::discardLevel(LevelDetails key) { int bytesInLevel = _bytesInUse - key._startIndex; + + // reset statistics... + int reduceBytesOfOctalCodes = _bytesOfOctalCodes - key._bytesOfOctalCodes; + int reduceBytesOfBitMasks = _bytesOfBitMasks - key._bytesOfBitmasks; + int reduceBytesOfColor = _bytesOfColor - key._bytesOfColor; + + _bytesOfOctalCodes = key._bytesOfOctalCodes; + _bytesOfBitMasks = key._bytesOfBitmasks; + _bytesOfColor = key._bytesOfColor; + + _totalBytesOfOctalCodes -= reduceBytesOfOctalCodes; + _totalBytesOfBitMasks -= reduceBytesOfBitMasks; + _totalBytesOfColor -= reduceBytesOfColor; if (_debug) { printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n", @@ -201,6 +226,7 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) { bool success = append(bitmask); // handles checking compression if (success) { _bytesOfBitMasks++; + _totalBytesOfBitMasks++; } return success; } @@ -221,6 +247,7 @@ bool VoxelPacket::appendColor(const nodeColor& color) { } if (success) { _bytesOfColor += BYTES_PER_COLOR; + _totalBytesOfColor += BYTES_PER_COLOR; } return success; } diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index bb8b8bbb02..4edf21f033 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -113,6 +113,10 @@ public: static uint64_t _checkCompressTime; static uint64_t _checkCompressCalls; + + static uint64_t _totalBytesOfOctalCodes; + static uint64_t _totalBytesOfBitMasks; + static uint64_t _totalBytesOfColor; private: /// appends raw bytes, might fail if byte would cause packet to be too large @@ -137,10 +141,11 @@ private: bool _dirty; // statistics... - static uint64_t _bytesOfOctalCodes; - static uint64_t _bytesOfBitMasks; - static uint64_t _bytesOfColor; - + int _bytesOfOctalCodes; + int _bytesOfBitMasks; + int _bytesOfColor; + int _bytesOfOctalCodesCurrentSubTree; + static bool _debug; }; From 17f5530893adf0ef04830809aa99a4f728d29a1a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 01:42:19 -0800 Subject: [PATCH 54/77] fixed wasted bitmasks bug where we would include colors and extra layers --- libraries/shared/src/SharedUtil.cpp | 12 ++++++------ libraries/shared/src/SharedUtil.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 25 +++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 8c56c250e0..a915db2506 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -69,20 +69,20 @@ void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) } } -void outputBits(unsigned char byte, bool withNewLine) { +void outputBits(unsigned char byte, bool withNewLine, bool usePrintf) { if (isalnum(byte)) { - qDebug("[ %d (%c): ", byte, byte); + usePrintf ? (void)printf("[ %d (%c): ", byte, byte) : qDebug("[ %d (%c): ", byte, byte); } else { - qDebug("[ %d (0x%x): ", byte, byte); + usePrintf ? (void)printf("[ %d (0x%x): ", byte, byte) : qDebug("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - qDebug("%d", byte >> (7 - i) & 1); + usePrintf ? (void)printf("%d", byte >> (7 - i) & 1) : qDebug("%d", byte >> (7 - i) & 1); } - qDebug(" ] "); + usePrintf ? (void)printf(" ] ") : qDebug(" ] "); if (withNewLine) { - qDebug("\n"); + usePrintf ? (void)printf("\n") : qDebug("\n"); } } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 29298ab944..e0d87ea4a8 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -53,7 +53,7 @@ bool randomBoolean(); bool shouldDo(float desiredInterval, float deltaTime); void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine = true); -void outputBits(unsigned char byte, bool withNewLine = true); +void outputBits(unsigned char byte, bool withNewLine = true, bool usePrintf = false); void printVoxelCode(unsigned char* voxelCode); int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 06bdc12f02..857e39ca69 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1419,6 +1419,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, if (!childWasInView || (params.deltaViewFrustum && childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ + childrenColoredBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } else { @@ -1530,7 +1531,17 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // remember this for reshuffling recursiveSliceStarts[originalIndex] = packet->getUncompressedData() + packet->getUncompressedSize(); - int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); + int childTreeBytesOut = 0; + + // XXXBHG - Note, this seems like the correct logic here, if we included the color in this packet, then + // the LOD logic determined that the child nodes do not need to be visible... and if so, we shouldn't recurse + // them further. But... this isn't how the code has been for a while... but it's a major savings (~30%) and + // it seems to work correctly. I'd like to discuss... + // + // only recurse if we DIDN'T include colore on this level + if (!oneAtBit(childrenColoredBits, originalIndex)) { + childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); + } // remember this for reshuffling recursiveSliceSizes[originalIndex] = childTreeBytesOut; @@ -1612,9 +1623,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } } // end keepDiggingDeeper + // At this point all our BitMasks are complete... so let's output them to see how they compare... + /** + printf("This Level's BitMasks: childInTree:"); + outputBits(childrenExistInTreeBits, false, true); + printf(" childInPacket:"); + outputBits(childrenExistInPacketBits, false, true); + printf(" childrenColored:"); + outputBits(childrenColoredBits, false, true); + printf("\n"); + **/ + // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... - if (continueThisLevel) { continueThisLevel = packet->endLevel(thisLevelKey); } else { From 78a8f2d0cc6c4651af0d3fedee4301d12b1b8833 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 08:56:37 -0800 Subject: [PATCH 55/77] added comments --- libraries/voxels/src/VoxelPacket.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index 4edf21f033..d6aafe597f 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -6,11 +6,11 @@ // // TO DO: // -// * add stats tracking for number of bytes of octal code, bitmasks, and colors in a packet. -// - this is challenging, because you need to support the rollback of statistics when -// you discard a level or discard +// * add stats tracking for number of unique colors and consecutive identical colors. +// (as research for color dictionaries and RLE) // // * further testing of compression to determine optimal configuration for performance and compression +// // * improve semantics for "reshuffle" - current approach will work for now and with compression // but wouldn't work with RLE because the colors in the levels would get reordered and RLE would need // to be recalculated From 78d39ed948316cbfa3979184f6f86b9702fa498f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 10:41:07 -0800 Subject: [PATCH 56/77] added timing details for better debugging and results measurement --- .../src/VoxelSendThread.cpp | 17 +++++++++++++---- .../voxel-server-library/src/VoxelServer.cpp | 3 +++ libraries/voxels/src/VoxelPacket.h | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index f01b300cef..1e89289426 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -87,6 +87,7 @@ uint64_t VoxelSendThread::_totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { bool debug = true; // _myServer->wantsDebugVoxelSending(); + uint64_t now = usecTimestampNow(); bool packetSent = false; // did we send a packet? int packetsSent = 0; @@ -118,7 +119,8 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Adding stats to packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Adding stats to packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + now, _totalPackets, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); @@ -138,7 +140,8 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Sending separate stats packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Sending separate stats packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + now, _totalPackets, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); @@ -158,7 +161,8 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Sending packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Sending packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + now, _totalPackets, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); @@ -178,7 +182,8 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Sending packet [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Sending packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + now, _totalPackets, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); @@ -300,6 +305,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->nodeBag.deleteAll(); } + qDebug("Scene started at %llu. Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n", + usecTimestampNow(), _totalPackets, _totalBytes, _totalWastedBytes); + + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); // This is the start of "resending" the scene. diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 36db9ee1ca..94204c22f4 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -703,6 +703,9 @@ void VoxelServer::run() { int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] == PACKET_TYPE_VOXEL_QUERY) { + + qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow()); + // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader, diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index d6aafe597f..c3038691ac 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -9,6 +9,8 @@ // * add stats tracking for number of unique colors and consecutive identical colors. // (as research for color dictionaries and RLE) // +// * copy/paste broken? reset()? +// // * further testing of compression to determine optimal configuration for performance and compression // // * improve semantics for "reshuffle" - current approach will work for now and with compression From 66ebaae7c8301c0ad26f269f71574189a6bddac5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 13:34:53 -0800 Subject: [PATCH 57/77] added debugging/logging of sleep times removed bail early loging in send thread since it wasn't needed and reduced sending potential in high PPS case --- .../src/VoxelSendThread.cpp | 44 +++++++++++-------- .../src/VoxelSendThread.h | 3 ++ libraries/voxels/src/VoxelSceneStats.h | 2 + 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 1e89289426..65eb01ef7f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -8,16 +8,24 @@ // Threaded or non-threaded voxel packet sender // -#include -#include -#include #include +#include +#include +#include +#include + extern EnvironmentData environmentData[3]; + #include "VoxelSendThread.h" #include "VoxelServer.h" #include "VoxelServerConsts.h" + +uint64_t startSceneSleepTime = 0; +uint64_t endSceneSleepTime = 0; + + VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : _nodeUUID(nodeUUID), _myServer(myServer), @@ -69,6 +77,7 @@ bool VoxelSendThread::process() { int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { + PerformanceWarning warn(false,"VoxelSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { @@ -80,6 +89,8 @@ bool VoxelSendThread::process() { return isStillRunning(); // keep running till they terminate us } +uint64_t VoxelSendThread::_usleepTime = 0; +uint64_t VoxelSendThread::_usleepCalls = 0; uint64_t VoxelSendThread::_totalBytes = 0; uint64_t VoxelSendThread::_totalWastedBytes = 0; @@ -289,7 +300,17 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } if (_encodedSomething) { nodeData->stats.sceneCompleted(); + + ::endSceneSleepTime = _usleepTime; + unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + + unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); + unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + + qDebug("Scene completed at %llu. encodeTime: %lu sleepTime: %lu elapsed: %lu Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n", + usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); + } if (_myServer->wantDisplayVoxelStats()) { @@ -309,6 +330,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod usecTimestampNow(), _totalPackets, _totalBytes, _totalWastedBytes); + ::startSceneSleepTime = _usleepTime; nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); // This is the start of "resending" the scene. @@ -347,22 +369,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); } - - // Check to see if we're taking too long, and if so bail early... - uint64_t now = usecTimestampNow(); - long elapsedUsec = (now - start); - long elapsedUsecPerPacket = (truePacketsSent == 0) ? 0 : (elapsedUsec / truePacketsSent); - long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec); - - if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n", - usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket, - nodeData->nodeBag.count()); - } - break; - } - bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { VoxelNode* subTree = nodeData->nodeBag.extract(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index f088163f4d..423f3c0ef4 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -27,6 +27,9 @@ public: static uint64_t _totalWastedBytes; static uint64_t _totalPackets; + static uint64_t _usleepTime; + static uint64_t _usleepCalls; + protected: /// Implements generic processing behavior for this thread. virtual bool process(); diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index e273c57174..c6f1eec966 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -146,6 +146,8 @@ public: unsigned long getTotalVoxels() const { return _totalVoxels; } unsigned long getTotalInternal() const { return _totalInternal; } unsigned long getTotalLeaves() const { return _totalLeaves; } + unsigned long getTotalEncodeTime() const { return _totalEncodeTime; } + unsigned long getElapsedTime() const { return _elapsed; } private: From de26b950f8671ace2ccb7ad2e31e694da2e32c76 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 14:25:09 -0800 Subject: [PATCH 58/77] cleanup menu defaults --- interface/src/Application.cpp | 12 +++++------- interface/src/Menu.cpp | 16 ++++++++-------- interface/src/Menu.h | 8 ++++---- libraries/voxels/src/VoxelPacket.h | 2 +- libraries/voxels/src/VoxelQuery.cpp | 2 +- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58629df41e..f3917a6b8e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -686,9 +686,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_C: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::OcclusionCulling); - } else if (_nudgeStarted) { + if (_nudgeStarted) { _nudgeGuidePosition.y -= _mouseVoxel.s; } else { _myAvatar.setDriveKeys(DOWN, 1); @@ -2580,10 +2578,10 @@ void Application::queryVoxels() { bool wantExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. - _voxelQuery.setWantLowResMoving(Menu::getInstance()->isOptionChecked(MenuOption::LowRes)); - _voxelQuery.setWantColor(Menu::getInstance()->isOptionChecked(MenuOption::SendVoxelColors)); - _voxelQuery.setWantDelta(Menu::getInstance()->isOptionChecked(MenuOption::DeltaSending)); - _voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::OcclusionCulling)); + _voxelQuery.setWantLowResMoving(!Menu::getInstance()->isOptionChecked(MenuOption::DisableLowRes)); + _voxelQuery.setWantColor(!Menu::getInstance()->isOptionChecked(MenuOption::DisableColorVoxels)); + _voxelQuery.setWantDelta(!Menu::getInstance()->isOptionChecked(MenuOption::DisableDeltaSending)); + _voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::EnableOcclusionCulling)); _voxelQuery.setCameraPosition(_viewFrustum.getPosition()); _voxelQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fd942a77c1..d5bdff3d8a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -297,6 +297,14 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); + QMenu* voxelProtoOptionsMenu = voxelOptionsMenu->addMenu("Voxel Server Protocol Options"); + + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableColorVoxels); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableLowRes); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableDeltaSending); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableOcclusionCulling); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); + QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options"); addDisabledActionAndSeparator(cullingOptionsMenu, "Standard Settings"); addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::OldVoxelCullingMode, 0, @@ -486,14 +494,6 @@ Menu::Menu() : QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio); - QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options"); - - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::SendVoxelColors); - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::LowRes); - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DeltaSending); - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::OcclusionCulling); - addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::ExtraDebugging); addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, Qt::CTRL | Qt::SHIFT | Qt::Key_V, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index db8b0ed528..8b832d7bbd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -161,14 +161,17 @@ namespace MenuOption { const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DeleteVoxels = "Delete"; const QString DestructiveAddVoxel = "Create Voxel is Destructive"; - const QString DeltaSending = "Delta Sending"; + const QString DisableColorVoxels = "Disable Colored Voxels"; const QString DisableConstantCulling = "Disable Constant Culling"; + const QString DisableDeltaSending = "Disable Delta Sending"; const QString DisableFastVoxelPipeline = "Disable Fast Voxel Pipeline"; + const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayLeapHands = "Display Leap Hands"; const QString DontRenderVoxels = "Don't call _voxels.render()"; const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels"; const QString EchoAudio = "Echo Audio"; + const QString EnableOcclusionCulling = "Enable Occlusion Culling"; const QString ExportVoxels = "Export Voxels"; const QString ExtraDebugging = "Extra Debugging"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; @@ -206,12 +209,10 @@ namespace MenuOption { const QString Login = "Login"; const QString LookAtIndicator = "Look-at Indicator"; const QString LookAtVectors = "Look-at Vectors"; - const QString LowRes = "Lower Resolution While Moving"; const QString Mirror = "Mirror"; const QString MoveWithLean = "Move with Lean"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString NudgeVoxels = "Nudge"; - const QString OcclusionCulling = "Occlusion Culling"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString TurnWithHead = "Turn using Head"; @@ -227,7 +228,6 @@ namespace MenuOption { const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetSwatchColors = "Reset Swatch Colors"; const QString RunTimingTests = "Run Timing Tests"; - const QString SendVoxelColors = "Colored Voxels"; const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; const QString SettingsExport = "Export Settings"; diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index c3038691ac..b8301cacf2 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -9,7 +9,7 @@ // * add stats tracking for number of unique colors and consecutive identical colors. // (as research for color dictionaries and RLE) // -// * copy/paste broken? reset()? +// * copy/paste broken? // // * further testing of compression to determine optimal configuration for performance and compression // diff --git a/libraries/voxels/src/VoxelQuery.cpp b/libraries/voxels/src/VoxelQuery.cpp index ec43a3a092..ac39ea5c4c 100644 --- a/libraries/voxels/src/VoxelQuery.cpp +++ b/libraries/voxels/src/VoxelQuery.cpp @@ -34,7 +34,7 @@ VoxelQuery::VoxelQuery(Node* owningNode) : _wantColor(true), _wantDelta(true), _wantLowResMoving(true), - _wantOcclusionCulling(true), + _wantOcclusionCulling(false), // disabled by default _maxVoxelPPS(DEFAULT_MAX_VOXEL_PPS), _voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE) { From d13ebf6095e076d9c78af05e644bf7ab22844a84 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 14:44:34 -0800 Subject: [PATCH 59/77] more menu cleanup removing developer options that are now defunct --- interface/src/Application.cpp | 4 +-- interface/src/Menu.cpp | 44 --------------------------- interface/src/Menu.h | 8 ----- interface/src/VoxelSystem.cpp | 11 ++++--- libraries/voxels/src/VoxelConstants.h | 2 +- 5 files changed, 10 insertions(+), 59 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3917a6b8e..79488e5f04 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1771,7 +1771,7 @@ void Application::init() { _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); _voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader)); _voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints)); - _voxels.setDisableFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::DisableFastVoxelPipeline)); + _voxels.setDisableFastVoxelPipeline(false); _voxels.init(); @@ -3609,7 +3609,7 @@ void Application::displayStats() { // Voxel Rendering voxelStats.str(""); voxelStats.precision(4); - voxelStats << "Voxel Rendering Slots" << + voxelStats << "Voxel Rendering Slots " << "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d5bdff3d8a..0913858fc1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -305,23 +305,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableOcclusionCulling); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); - QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options"); - addDisabledActionAndSeparator(cullingOptionsMenu, "Standard Settings"); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::OldVoxelCullingMode, 0, - false, this, SLOT(setOldVoxelCullingMode(bool))); - - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::NewVoxelCullingMode, 0, - false, this, SLOT(setNewVoxelCullingMode(bool))); - - addDisabledActionAndSeparator(cullingOptionsMenu, "Individual Option Settings"); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::DisableFastVoxelPipeline, 0, - false, appInstance->getVoxels(), SLOT(setDisableFastVoxelPipeline(bool))); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::DisableHideOutOfView); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::RemoveOutOfView); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::UseFullFrustumInHide); - addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::DisableConstantCulling); - - QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); @@ -1138,30 +1121,3 @@ void Menu::updateFrustumRenderModeAction() { } } -void Menu::setOldVoxelCullingMode(bool oldMode) { - setVoxelCullingMode(oldMode); -} - -void Menu::setNewVoxelCullingMode(bool newMode) { - setVoxelCullingMode(!newMode); -} - -/// This will switch on or off several different individual settings options all at once based on choosing with Old or New -/// voxel culling mode. -void Menu::setVoxelCullingMode(bool oldMode) { - const QString menus[] = { MenuOption::DisableFastVoxelPipeline, MenuOption::RemoveOutOfView, MenuOption::DisableHideOutOfView, - MenuOption::UseFullFrustumInHide, MenuOption::DisableConstantCulling}; - bool oldModeValue[] = { true, true, true, true, true }; - bool newModeValue[] = { false, false, false, false, false }; - - for (int i = 0; i < sizeof(menus) / sizeof(menus[0]); i++) { - bool desiredValue = oldMode ? oldModeValue[i] : newModeValue[i]; - if (isOptionChecked(menus[i]) != desiredValue) { - triggerOption(menus[i]); - } - } - - // set the checkmarks accordingly... - _actionHash.value(MenuOption::OldVoxelCullingMode)->setChecked(oldMode); - _actionHash.value(MenuOption::NewVoxelCullingMode)->setChecked(!oldMode); -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8b832d7bbd..6f5978be8a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -93,8 +93,6 @@ private slots: void chooseVoxelPaintColor(); void runTests(); void resetSwatchColors(); - void setOldVoxelCullingMode(bool oldMode); - void setNewVoxelCullingMode(bool newMode); private: static Menu* _instance; @@ -124,7 +122,6 @@ private: const char* member = NULL); void updateFrustumRenderModeAction(); - void setVoxelCullingMode(bool oldMode); QHash _actionHash; int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback @@ -162,9 +159,7 @@ namespace MenuOption { const QString DeleteVoxels = "Delete"; const QString DestructiveAddVoxel = "Create Voxel is Destructive"; const QString DisableColorVoxels = "Disable Colored Voxels"; - const QString DisableConstantCulling = "Disable Constant Culling"; const QString DisableDeltaSending = "Disable Delta Sending"; - const QString DisableFastVoxelPipeline = "Disable Fast Voxel Pipeline"; const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayLeapHands = "Display Leap Hands"; @@ -193,7 +188,6 @@ namespace MenuOption { const QString GlowMode = "Cycle Glow Mode"; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; - const QString DisableHideOutOfView = "Disable Hide Out of View Voxels"; const QString GoToUser = "Go To User..."; const QString ImportVoxels = "Import Voxels"; const QString ImportVoxelsClipboard = "Import Voxels to Clipboard"; @@ -224,7 +218,6 @@ namespace MenuOption { const QString PipelineWarnings = "Show Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString RandomizeVoxelColors = "Randomize Voxel TRUE Colors"; - const QString RemoveOutOfView = "Instead of Hide Remove Out of View Voxels"; const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetSwatchColors = "Reset Swatch Colors"; const QString RunTimingTests = "Run Timing Tests"; @@ -244,7 +237,6 @@ namespace MenuOption { const QString TreeStats = "Calculate Tree Stats"; const QString TransmitterDrive = "Transmitter Drive"; const QString Quit = "Quit"; - const QString UseFullFrustumInHide = "Use Full View Frustums when Culling"; const QString UseVoxelShader = "Use Voxel Shader"; const QString VoxelsAsPoints = "Draw Voxels as Points"; const QString Voxels = "Voxels"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 627c86ef93..9e82c61351 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -774,7 +774,10 @@ void VoxelSystem::checkForCulling() { uint64_t start = usecTimestampNow(); uint64_t sinceLastViewCulling = (start - _lastViewCulling) / 1000; - bool constantCulling = !Menu::getInstance()->isOptionChecked(MenuOption::DisableConstantCulling); + // These items used to be menu options, we are not defaulting to and only supporting these modes. + bool constantCulling = true; + bool performHideOutOfViewLogic = true; + bool performRemoveOutOfViewLogic = false; // If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view if (constantCulling || ( @@ -785,7 +788,7 @@ void VoxelSystem::checkForCulling() { // When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove // them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which // can be expensive). - if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableHideOutOfView)) { + if (performHideOutOfViewLogic) { // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if // it's been a long time since we last moved, then go ahead and do a full frustum cull. @@ -819,7 +822,7 @@ void VoxelSystem::checkForCulling() { _lastViewCullingElapsed = (endViewCulling - start) / 1000; } - } else if (Menu::getInstance()->isOptionChecked(MenuOption::RemoveOutOfView)) { + } else if (performRemoveOutOfViewLogic) { _lastViewCulling = start; removeOutOfView(); uint64_t endViewCulling = usecTimestampNow(); @@ -1943,7 +1946,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { // Both these problems are solved by intermittently calling this with forceFullFrustum set // to true. This will essentially clean up the improperly hidden or shown voxels. // - bool wantDeltaFrustums = !forceFullFrustum && !Menu::getInstance()->isOptionChecked(MenuOption::UseFullFrustumInHide); + bool wantDeltaFrustums = !forceFullFrustum; hideOutOfViewArgs args(this, this->_tree, _culledOnce, widenFrustum, wantDeltaFrustums); const bool wantViewFrustumDebugging = false; // change to true for additional debugging diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 3a66f6f564..e9bc48f9b5 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -36,7 +36,7 @@ const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; const int MAX_TREE_SLICE_BYTES = 26; -const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 200000; +const int DEFAULT_MAX_VOXELS_PER_SYSTEM = 500000; const int VERTICES_PER_VOXEL = 24; // 6 sides * 4 corners per side const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; // xyz for each VERTICE_PER_VOXEL const int INDICES_PER_VOXEL = 3 * 12; // 6 sides * 2 triangles per size * 3 vertices per triangle From 63a82af449c329bd24153e308a5e59dc6ed3e8a8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 15:13:31 -0800 Subject: [PATCH 60/77] allow client to set voxels MaxPPS in Preferences --- interface/src/Application.cpp | 5 +++-- interface/src/Menu.cpp | 17 ++++++++++++++++- interface/src/Menu.h | 4 ++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 79488e5f04..49b1d28535 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2643,15 +2643,16 @@ void Application::queryVoxels() { int perServerPPS = 0; const int SMALL_BUDGET = 10; int perUnknownServer = SMALL_BUDGET; + int totalPPS = Menu::getInstance()->getMaxVoxelPacketsPerSecond(); // determine PPS based on number of servers if (inViewServers >= 1) { // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS // for each unknown jurisdiction server - perServerPPS = (DEFAULT_MAX_VOXEL_PPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); + perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); } else { if (unknownJurisdictionServers > 0) { - perUnknownServer = (DEFAULT_MAX_VOXEL_PPS / unknownJurisdictionServers); + perUnknownServer = (totalPPS / unknownJurisdictionServers); } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0913858fc1..ca3d72ed8f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -61,7 +61,8 @@ Menu::Menu() : _lodToolsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE), - _boundaryLevelAdjust(0) + _boundaryLevelAdjust(0), + _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS) { Application *appInstance = Application::getInstance(); @@ -506,6 +507,7 @@ void Menu::loadSettings(QSettings* settings) { _fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES); _faceshiftEyeDeflection = loadSetting(settings, "faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION); _maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM); + _maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS); _voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_VOXEL_SIZE_SCALE); _boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0); @@ -535,6 +537,7 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("fieldOfView", _fieldOfView); settings->setValue("faceshiftEyeDeflection", _faceshiftEyeDeflection); settings->setValue("maxVoxels", _maxVoxels); + settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond); settings->setValue("voxelSizeScale", _voxelSizeScale); settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust); settings->beginGroup("View Frustum Offset Camera"); @@ -815,6 +818,16 @@ void Menu::editPreferences() { maxVoxels->setSingleStep(STEP_MAX_VOXELS); maxVoxels->setValue(_maxVoxels); form->addRow("Maximum Voxels:", maxVoxels); + + QSpinBox* maxVoxelsPPS = new QSpinBox(); + const int MAX_MAX_VOXELS_PPS = 6000; + const int MIN_MAX_VOXELS_PPS = 60; + const int STEP_MAX_VOXELS_PPS = 10; + maxVoxelsPPS->setMaximum(MAX_MAX_VOXELS_PPS); + maxVoxelsPPS->setMinimum(MIN_MAX_VOXELS_PPS); + maxVoxelsPPS->setSingleStep(STEP_MAX_VOXELS_PPS); + maxVoxelsPPS->setValue(_maxVoxelPacketsPerSecond); + form->addRow("Maximum Voxels Packets Per Second:", maxVoxelsPPS); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); @@ -854,6 +867,8 @@ void Menu::editPreferences() { _maxVoxels = maxVoxels->value(); applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels); + + _maxVoxelPacketsPerSecond = maxVoxelsPPS->value(); applicationInstance->getAvatar()->setLeanScale(leanScale->value()); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6f5978be8a..3696cb4cff 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -68,6 +68,9 @@ public: void setBoundaryLevelAdjust(int boundaryLevelAdjust); int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } + // User Tweakable PPS from Voxel Server + int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; } + public slots: void bandwidthDetails(); void voxelStatsDetails(); @@ -137,6 +140,7 @@ private: float _voxelSizeScale; int _boundaryLevelAdjust; QAction* _useVoxelShader; + int _maxVoxelPacketsPerSecond; }; namespace MenuOption { From a60cf0f34ea74b2571d64d685644a3bb5d85cb78 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 25 Nov 2013 15:52:30 -0800 Subject: [PATCH 61/77] fix issue with copy --- interface/src/Application.cpp | 7 ++----- libraries/voxels/src/VoxelPacket.h | 2 -- libraries/voxels/src/VoxelTree.cpp | 18 +++++++++--------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 49b1d28535..6005c455b6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1524,7 +1524,6 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; if (node->isColored()) { const unsigned char* nodeOctalCode = node->getOctalCode(); - unsigned char* codeColorBuffer = NULL; int codeLength = 0; int bytesInCode = 0; @@ -1545,10 +1544,9 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { } // copy the colors over - codeColorBuffer[bytesInCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; + codeColorBuffer[bytesInCode + RED_INDEX] = node->getColor()[RED_INDEX]; codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; - codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; - + codeColorBuffer[bytesInCode + BLUE_INDEX] = node->getColor()[BLUE_INDEX]; getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, codeColorBuffer, codeAndColorLength); @@ -1612,7 +1610,6 @@ void Application::pasteVoxelsToOctalCode(const unsigned char* octalCodeDestinati // the server as an set voxel message, this will also rebase the voxels to the new location SendVoxelsOperationArgs args; args.newBaseOctCode = octalCodeDestination; - _sharedVoxelSystem.getTree()->recurseTreeWithOperation(sendVoxelsOperation, &args); if (_sharedVoxelSystem.getTree() != &_clipboard) { diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacket.h index b8301cacf2..d6aafe597f 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacket.h @@ -9,8 +9,6 @@ // * add stats tracking for number of unique colors and consecutive identical colors. // (as research for color dictionaries and RLE) // -// * copy/paste broken? -// // * further testing of compression to determine optimal configuration for performance and compression // // * improve semantics for "reshuffle" - current approach will work for now and with compression diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 857e39ca69..2b9fb98082 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1534,12 +1534,15 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, int childTreeBytesOut = 0; // XXXBHG - Note, this seems like the correct logic here, if we included the color in this packet, then - // the LOD logic determined that the child nodes do not need to be visible... and if so, we shouldn't recurse - // them further. But... this isn't how the code has been for a while... but it's a major savings (~30%) and - // it seems to work correctly. I'd like to discuss... - // - // only recurse if we DIDN'T include colore on this level - if (!oneAtBit(childrenColoredBits, originalIndex)) { + // the LOD logic determined that the child nodes would not be visible... and if so, we shouldn't recurse + // them further. But... for some time now the code has included and recursed into these child nodes, which + // would likely still send the child content, even though the client wouldn't render it. This change is + // a major savings (~30%) and it seems to work correctly. But I want us to discuss as a group when we do + // a voxel protocol review. + // + // This only applies in the view frustum case, in other cases, like file save and copy/past where + // no viewFrustum was requested, we still want to recurse the child tree. + if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); } @@ -1916,13 +1919,10 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - packet.reset(); // reset the packet between usage - // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); - // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); destinationTree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); From 491512fbce528392aca8ad9ca7256e0aa8fcd14c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 17:26:54 -0800 Subject: [PATCH 62/77] major pass on cleaning up voxel packets to have flags, sequence numbers, and flight time, add compression menu item --- libraries/shared/src/PacketHeaders.cpp | 3 + libraries/shared/src/PacketHeaders.h | 2 - .../src/VoxelNodeData.cpp | 36 +++++- .../voxel-server-library/src/VoxelNodeData.h | 33 +++-- .../src/VoxelSendThread.cpp | 75 ++++++----- .../src/VoxelSendThread.h | 2 +- .../voxel-server-library/src/VoxelServer.cpp | 29 ++--- .../src/VoxelServerPacketProcessor.cpp | 29 ----- .../{VoxelPacket.cpp => VoxelPacketData.cpp} | 122 +++++++++--------- .../src/{VoxelPacket.h => VoxelPacketData.h} | 44 ++++--- libraries/voxels/src/VoxelQuery.cpp | 9 +- libraries/voxels/src/VoxelQuery.h | 6 +- libraries/voxels/src/VoxelTree.cpp | 70 +++++----- libraries/voxels/src/VoxelTree.h | 6 +- 14 files changed, 246 insertions(+), 220 deletions(-) rename libraries/voxels/src/{VoxelPacket.cpp => VoxelPacketData.cpp} (69%) rename libraries/voxels/src/{VoxelPacket.h => VoxelPacketData.h} (81%) diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b03daeec05..1bd71e35eb 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -43,6 +43,9 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: case PACKET_TYPE_ERASE_VOXEL: return 1; + + case PACKET_TYPE_VOXEL_DATA: + return 1; default: return 0; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 64a6544cfa..9f19291eff 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -20,7 +20,6 @@ const PACKET_TYPE PACKET_TYPE_PING = 'P'; const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R'; const PACKET_TYPE PACKET_TYPE_KILL_NODE = 'K'; const PACKET_TYPE PACKET_TYPE_HEAD_DATA = 'H'; -const PACKET_TYPE PACKET_TYPE_Z_COMMAND = 'Z'; const PACKET_TYPE PACKET_TYPE_INJECT_AUDIO = 'I'; const PACKET_TYPE PACKET_TYPE_MIXED_AUDIO = 'A'; const PACKET_TYPE PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO = 'M'; @@ -41,7 +40,6 @@ const PACKET_TYPE PACKET_TYPE_DATA_SERVER_SEND = 'u'; const PACKET_TYPE PACKET_TYPE_DATA_SERVER_CONFIRM = 'c'; const PACKET_TYPE PACKET_TYPE_VOXEL_QUERY = 'q'; const PACKET_TYPE PACKET_TYPE_VOXEL_DATA = 'V'; -const PACKET_TYPE PACKET_TYPE_VOXEL_DATA_MONOCHROME = 'v'; const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#'; const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION = 'J'; const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION_REQUEST = 'j'; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 6b7b704bf1..8068c57bcc 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -23,6 +23,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _viewFrustumChanging(false), _viewFrustumJustStoppedChanging(true), _currentPacketIsColor(true), + _currentPacketIsCompressed(false), _voxelSendThread(NULL), _lastClientBoundaryLevelAdjust(0), _lastClientVoxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE), @@ -34,6 +35,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; + _sequenceNumber = 0; resetVoxelPacket(); } @@ -96,12 +98,37 @@ void VoxelNodeData::resetVoxelPacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsColor = (LOW_RES_MONO && getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor(); - PACKET_TYPE voxelPacketType = _currentPacketIsColor ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME; + _currentPacketIsColor = getWantColor(); + _currentPacketIsCompressed = getWantCompression(); + VOXEL_PACKET_FLAGS flags = 0; + if (_currentPacketIsColor) { + setAtBit(flags,PACKET_IS_COLOR_BIT); + } + if (_currentPacketIsCompressed) { + setAtBit(flags,PACKET_IS_COMPRESSED_BIT); + } - int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); + int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; + + // pack in flags + VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt; + *flagsAt = flags; + _voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS); + + // pack in sequence number + VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt; + *sequenceAt = _sequenceNumber; + _voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE); + _sequenceNumber++; + + // pack in timestamp + VOXEL_PACKET_SENT_TIME now = usecTimestampNow(); + VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt; + *timeAt = now; + _voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME); + + _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_DATA_SIZE; _voxelPacketWaiting = false; } @@ -181,7 +208,6 @@ void VoxelNodeData::setViewSent(bool viewSent) { } } - void VoxelNodeData::updateLastKnownViewFrustum() { bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 081844ac08..bc6409b10c 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -39,36 +39,40 @@ public: bool shouldSuppressDuplicatePacket(); int getAvailable() const { return _voxelPacketAvailableBytes; } - int getMaxSearchLevel() const { return _maxSearchLevel; }; - void resetMaxSearchLevel() { _maxSearchLevel = 1; }; - void incrementMaxSearchLevel() { _maxSearchLevel++; }; + int getMaxSearchLevel() const { return _maxSearchLevel; } + void resetMaxSearchLevel() { _maxSearchLevel = 1; } + void incrementMaxSearchLevel() { _maxSearchLevel++; } - int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; }; + int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; } void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } VoxelNodeBag nodeBag; CoverageMap map; - ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; - ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; + ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } + ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; } // These are not classic setters because they are calculating and maintaining state // which is set asynchronously through the network receive bool updateCurrentViewFrustum(); void updateLastKnownViewFrustum(); - bool getViewSent() const { return _viewSent; }; + bool getViewSent() const { return _viewSent; } void setViewSent(bool viewSent); - bool getViewFrustumChanging() const { return _viewFrustumChanging; }; - bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; }; + bool getViewFrustumChanging() const { return _viewFrustumChanging; } + bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; } bool moveShouldDump() const; - uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; - void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; + uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; } + void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; } - bool getCurrentPacketIsColor() const { return _currentPacketIsColor; }; + bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } + bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } + bool getCurrentPacketFormatMatches() { + return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + } bool hasLodChanged() const { return _lodChanged; }; @@ -102,6 +106,7 @@ private: bool _viewFrustumChanging; bool _viewFrustumJustStoppedChanging; bool _currentPacketIsColor; + bool _currentPacketIsCompressed; VoxelSendThread* _voxelSendThread; @@ -110,6 +115,8 @@ private: float _lastClientVoxelSizeScale; bool _lodChanged; bool _lodInitialized; + + VOXEL_PACKET_SEQUENCE _sequenceNumber; }; #endif /* defined(__hifi__VoxelNodeData__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 65eb01ef7f..889834b183 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -29,7 +29,7 @@ uint64_t endSceneSleepTime = 0; VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : _nodeUUID(nodeUUID), _myServer(myServer), - _tempPacket(VOXEL_PACKET_COMPRESSION_DEFAULT), + _packetData(), _encodedSomething(false) { } @@ -228,32 +228,37 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantColor = LOW_RES_MONO && nodeData->getWantLowResMoving() && viewFrustumChanged ? false : nodeData->getWantColor(); + bool wantColor = nodeData->getWantColor(); + bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. - if (wantColor != nodeData->getCurrentPacketIsColor()) { - + if (!nodeData->getCurrentPacketFormatMatches()) { if (nodeData->isPacketWaiting()) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); + printf("wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", + debug::valueOf(wantColor), debug::valueOf(wantCompression), + debug::valueOf(nodeData->getCurrentPacketIsColor()), + debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); } - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); + printf("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", + debug::valueOf(wantColor), debug::valueOf(wantCompression), + debug::valueOf(nodeData->getCurrentPacketIsColor()), + debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); } nodeData->resetVoxelPacket(); } + _packetData.changeSettings(wantCompression); } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); + if (true || (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug())) { + printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n", + debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), + debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), + debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); } const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -308,8 +313,16 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - qDebug("Scene completed at %llu. encodeTime: %lu sleepTime: %lu elapsed: %lu Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n", - usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); + bool debug = false; + if (debug) { + qDebug() << "Scene completed at " << usecTimestampNow() << + " encodeTime: "<< encodeTime << + " sleepTime: " << sleepTime << + " elapsed: "<< elapsedTime << + " Packets:["<< _totalPackets <<"]"<< + " Total Bytes:["<< _totalBytes <<"]"<< + " Wasted bytes:["<< _totalWastedBytes << "]\n"; + } } @@ -326,9 +339,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->nodeBag.deleteAll(); } - qDebug("Scene started at %llu. Packets:[%llu]: Total Bytes:[%llu] Wasted bytes:[%llu]\n", - usecTimestampNow(), _totalPackets, _totalBytes, _totalWastedBytes); - + bool debug = false; + if (debug) { + qDebug() << "Scene started at " << usecTimestampNow() << + " Packets:["<< _totalPackets <<"]"<< + " Total Bytes:["<< _totalBytes <<"]"<< + " Wasted bytes:["<< _totalWastedBytes << "]\n"; + } ::startSceneSleepTime = _usleepTime; nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); @@ -348,8 +365,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; uint64_t start = usecTimestampNow(); - uint64_t startCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; - uint64_t startCompressCalls = VoxelPacket::_checkCompressCalls; + uint64_t startCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000; + uint64_t startCompressCalls = VoxelPacketData::_checkCompressCalls; bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); @@ -394,9 +411,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); + bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); - if (_tempPacket.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { + if (_packetData.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { lastNodeDidntFit = true; } @@ -411,18 +428,18 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod somethingToSend = false; // this will cause us to drop out of the loop... } - // We only consider sending anything if there is something in the _tempPacket to send... But + // We only consider sending anything if there is something in the _packetData to send... But // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. bool sendNow = lastNodeDidntFit; - if (_tempPacket.hasContent() && sendNow) { + if (_packetData.hasContent() && sendNow) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", - _tempPacket.getFinalizedSize(), _tempPacket.getUncompressedSize()); + _packetData.getFinalizedSize(), _packetData.getUncompressedSize()); } - nodeData->writeToPacket(_tempPacket.getFinalizedData(), _tempPacket.getFinalizedSize()); + nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - _tempPacket.reset(); + _packetData.reset(); } } @@ -445,10 +462,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start)/1000; - uint64_t endCompressCalls = VoxelPacket::_checkCompressCalls; + uint64_t endCompressCalls = VoxelPacketData::_checkCompressCalls; int elapsedCompressCalls = endCompressCalls - startCompressCalls; - uint64_t endCompressTimeMsecs = VoxelPacket::_checkCompressTime / 1000; + uint64_t endCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000; int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 423f3c0ef4..f4ded44abd 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -42,7 +42,7 @@ private: int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged); unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; // used by environment sending code - VoxelPacket _tempPacket; + VoxelPacketData _packetData; bool _encodedSomething; }; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 94204c22f4..d0c2a5bca5 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -268,9 +268,9 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { uint64_t totalOutboundPackets = VoxelSendThread::_totalPackets; uint64_t totalOutboundBytes = VoxelSendThread::_totalBytes; uint64_t totalWastedBytes = VoxelSendThread::_totalWastedBytes; - uint64_t totalBytesOfOctalCodes = VoxelPacket::_totalBytesOfOctalCodes; - uint64_t totalBytesOfBitMasks = VoxelPacket::_totalBytesOfBitMasks; - uint64_t totalBytesOfColor = VoxelPacket::_totalBytesOfColor; + uint64_t totalBytesOfOctalCodes = VoxelPacketData::_totalBytesOfOctalCodes; + uint64_t totalBytesOfBitMasks = VoxelPacketData::_totalBytesOfBitMasks; + uint64_t totalBytesOfColor = VoxelPacketData::_totalBytesOfColor; const int COLUMN_WIDTH = 10; mg_printf(connection, " Total Outbound Packets: %s packets\r\n", @@ -703,8 +703,10 @@ void VoxelServer::run() { int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] == PACKET_TYPE_VOXEL_QUERY) { - - qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow()); + bool debug = false; + if (debug) { + qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow()); + } // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. @@ -732,8 +734,7 @@ void VoxelServer::run() { } else if (_voxelServerPacketProcessor && (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE - || packetData[0] == PACKET_TYPE_ERASE_VOXEL - || packetData[0] == PACKET_TYPE_Z_COMMAND)) { + || packetData[0] == PACKET_TYPE_ERASE_VOXEL)) { const char* messageName; @@ -748,20 +749,6 @@ void VoxelServer::run() { messageName = "PACKET_TYPE_ERASE_VOXEL"; break; } - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - if (packetData[0] != PACKET_TYPE_Z_COMMAND) { - unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); - uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); - uint64_t arrivedAt = usecTimestampNow(); - uint64_t transitTime = arrivedAt - sentAt; - if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) { - printf("RECEIVE THREAD: got %s - command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", - messageName, - packetLength, sequence, transitTime); - } - } - _voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); } else { // let processNodeData handle it. diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 2581c923f5..d1449f72ea 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -169,35 +169,6 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned _myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength); _myServer->getServerTree().unlock(); - // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); - if (node) { - node->setLastHeardMicrostamp(usecTimestampNow()); - } - } else if (packetData[0] == PACKET_TYPE_Z_COMMAND) { - - // the Z command is a special command that allows the sender to send the voxel server high level semantic - // requests, like erase all, or add sphere scene - - char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command - int commandLength = strlen(command); // commands are null terminated strings - int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination - printf("got Z message len(%ld)= %s\n", packetLength, command); - bool rebroadcast = true; // by default rebroadcast - - while (totalLength <= packetLength) { - if (strcmp(command, TEST_COMMAND) == 0) { - printf("got Z message == a message, nothing to do, just report\n"); - } - totalLength += commandLength + 1; // 1 for null termination - } - - if (rebroadcast) { - // Now send this to the connected nodes so they can also process these messages - printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n"); - NodeList::getInstance()->broadcastToNodes(packetData, packetLength, &NODE_TYPE_AGENT, 1); - } - // Make sure our Node and NodeList knows we've heard from this node. Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (node) { diff --git a/libraries/voxels/src/VoxelPacket.cpp b/libraries/voxels/src/VoxelPacketData.cpp similarity index 69% rename from libraries/voxels/src/VoxelPacket.cpp rename to libraries/voxels/src/VoxelPacketData.cpp index f0d2c97ace..c403e582f1 100644 --- a/libraries/voxels/src/VoxelPacket.cpp +++ b/libraries/voxels/src/VoxelPacketData.cpp @@ -1,5 +1,5 @@ // -// VoxelPacket.cpp +// VoxelPacketData.cpp // hifi // // Created by Brad Hefta-Gaub on 11/19/2013. @@ -7,27 +7,31 @@ // #include -#include "VoxelPacket.h" +#include "VoxelPacketData.h" -bool VoxelPacket::_debug = false; -uint64_t VoxelPacket::_totalBytesOfOctalCodes = 0; -uint64_t VoxelPacket::_totalBytesOfBitMasks = 0; -uint64_t VoxelPacket::_totalBytesOfColor = 0; +bool VoxelPacketData::_debug = false; +uint64_t VoxelPacketData::_totalBytesOfOctalCodes = 0; +uint64_t VoxelPacketData::_totalBytesOfBitMasks = 0; +uint64_t VoxelPacketData::_totalBytesOfColor = 0; -VoxelPacket::VoxelPacket(bool enableCompression, int maxFinalizedSize) { +VoxelPacketData::VoxelPacketData(bool enableCompression, int targetSize) { + changeSettings(enableCompression, targetSize); // does reset... +} + +void VoxelPacketData::changeSettings(bool enableCompression, int targetSize) { _enableCompression = enableCompression; - _maxFinalizedSize = maxFinalizedSize; + _targetSize = std::min(MAX_VOXEL_UNCOMRESSED_PACKET_SIZE, targetSize); reset(); } -void VoxelPacket::reset() { +void VoxelPacketData::reset() { _bytesInUse = 0; if (_enableCompression) { _bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE; } else { - _bytesAvailable = _maxFinalizedSize; + _bytesAvailable = _targetSize; } _subTreeAt = 0; _compressedBytes = 0; @@ -40,10 +44,10 @@ void VoxelPacket::reset() { _bytesOfOctalCodesCurrentSubTree = 0; } -VoxelPacket::~VoxelPacket() { +VoxelPacketData::~VoxelPacketData() { } -bool VoxelPacket::append(const unsigned char* data, int length) { +bool VoxelPacketData::append(const unsigned char* data, int length) { bool success = false; if (length <= _bytesAvailable) { @@ -56,7 +60,7 @@ bool VoxelPacket::append(const unsigned char* data, int length) { return success; } -bool VoxelPacket::append(unsigned char byte) { +bool VoxelPacketData::append(unsigned char byte) { bool success = false; if (_bytesAvailable > 0) { _uncompressed[_bytesInUse] = byte; @@ -68,7 +72,7 @@ bool VoxelPacket::append(unsigned char byte) { return success; } -bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { +bool VoxelPacketData::updatePriorBitMask(int offset, unsigned char bitmask) { bool success = false; if (offset >= 0 && offset < _bytesInUse) { _uncompressed[offset] = bitmask; @@ -78,7 +82,7 @@ bool VoxelPacket::updatePriorBitMask(int offset, unsigned char bitmask) { return success; } -bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) { +bool VoxelPacketData::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) { bool success = false; if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) { memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content @@ -88,7 +92,7 @@ bool VoxelPacket::updatePriorBytes(int offset, const unsigned char* replacementB return success; } -bool VoxelPacket::startSubTree(const unsigned char* octcode) { +bool VoxelPacketData::startSubTree(const unsigned char* octcode) { _bytesOfOctalCodesCurrentSubTree = _bytesOfOctalCodes; bool success = false; int possibleStartAt = _bytesInUse; @@ -112,10 +116,11 @@ bool VoxelPacket::startSubTree(const unsigned char* octcode) { return success; } -const unsigned char* VoxelPacket::getFinalizedData() { +const unsigned char* VoxelPacketData::getFinalizedData() { if (!_enableCompression) { return &_uncompressed[0]; } + if (_dirty) { if (_debug) { @@ -124,10 +129,12 @@ const unsigned char* VoxelPacket::getFinalizedData() { checkCompress(); } +printf("VoxelPacketData::getFinalizedData()... _bytesInUse=%d compressed version..._compressedBytes=%d\n",_bytesInUse, _compressedBytes); + return &_compressed[0]; } -int VoxelPacket::getFinalizedSize() { +int VoxelPacketData::getFinalizedSize() { if (!_enableCompression) { return _bytesInUse; } @@ -143,11 +150,11 @@ int VoxelPacket::getFinalizedSize() { } -void VoxelPacket::endSubTree() { +void VoxelPacketData::endSubTree() { _subTreeAt = _bytesInUse; } -void VoxelPacket::discardSubTree() { +void VoxelPacketData::discardSubTree() { int bytesInSubTree = _bytesInUse - _subTreeAt; _bytesInUse -= bytesInSubTree; _bytesAvailable += bytesInSubTree; @@ -160,12 +167,12 @@ void VoxelPacket::discardSubTree() { _totalBytesOfOctalCodes -= reduceBytesOfOctalCodes; } -LevelDetails VoxelPacket::startLevel() { +LevelDetails VoxelPacketData::startLevel() { LevelDetails key(_bytesInUse, _bytesOfOctalCodes, _bytesOfBitMasks, _bytesOfColor); return key; } -void VoxelPacket::discardLevel(LevelDetails key) { +void VoxelPacketData::discardLevel(LevelDetails key) { int bytesInLevel = _bytesInUse - key._startIndex; // reset statistics... @@ -196,33 +203,12 @@ void VoxelPacket::discardLevel(LevelDetails key) { } } -bool VoxelPacket::endLevel(LevelDetails key) { +bool VoxelPacketData::endLevel(LevelDetails key) { bool success = true; - - // if we are dirty (something has changed) then try a compression test in the following cases... - // 1) If we've previously compressed and our _compressedBytes are "close enough to our limit" that we want to keep - // testing to make sure we don't overflow... VOXEL_PACKET_ALWAYS_TEST_COMPRESSION_THRESHOLD - // 2) If we've passed the uncompressed size where we believe we might pass the compressed threshold, and we've added - // a sufficient number of uncompressed bytes - if (_dirty && ( - (_compressedBytes > VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD) || - ( (_bytesInUse > VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD) && - (_bytesInUse - _bytesInUseLastCheck > VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD) - ) - )) { - if (_debug) { - printf("endLevel() _dirty=%s _compressedBytes=%d _bytesInUse=%d\n", - debug::valueOf(_dirty), _compressedBytes, _bytesInUse); - } - success = checkCompress(); - } - if (!success) { - discardLevel(key); - } return success; } -bool VoxelPacket::appendBitMask(unsigned char bitmask) { +bool VoxelPacketData::appendBitMask(unsigned char bitmask) { bool success = append(bitmask); // handles checking compression if (success) { _bytesOfBitMasks++; @@ -231,7 +217,7 @@ bool VoxelPacket::appendBitMask(unsigned char bitmask) { return success; } -bool VoxelPacket::appendColor(const nodeColor& color) { +bool VoxelPacketData::appendColor(const nodeColor& color) { // eventually we can make this use a dictionary... bool success = false; const int BYTES_PER_COLOR = 3; @@ -252,11 +238,11 @@ bool VoxelPacket::appendColor(const nodeColor& color) { return success; } -uint64_t VoxelPacket::_checkCompressTime = 0; -uint64_t VoxelPacket::_checkCompressCalls = 0; +uint64_t VoxelPacketData::_checkCompressTime = 0; +uint64_t VoxelPacketData::_checkCompressCalls = 0; -bool VoxelPacket::checkCompress() { - PerformanceWarning warn(false,"VoxelPacket::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls); +bool VoxelPacketData::checkCompress() { + PerformanceWarning warn(false,"VoxelPacketData::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls); // without compression, we always pass... if (!_enableCompression) { @@ -266,11 +252,15 @@ bool VoxelPacket::checkCompress() { _bytesInUseLastCheck = _bytesInUse; bool success = false; - const int MAX_COMPRESSION = 2; + const int MAX_COMPRESSION = 9; // we only want to compress the data payload, not the message header - QByteArray compressedData = qCompress(_uncompressed, _bytesInUse, MAX_COMPRESSION); - if (compressedData.size() < MAX_VOXEL_PACKET_SIZE) { + const uchar* uncompressedData = &_uncompressed[0]; + int uncompressedSize = _bytesInUse; + + QByteArray compressedData = qCompress(uncompressedData, uncompressedSize, MAX_COMPRESSION); + + if (compressedData.size() < MAX_VOXEL_PACKET_DATA_SIZE) { _compressedBytes = compressedData.size(); for (int i = 0; i < _compressedBytes; i++) { _compressed[i] = compressedData[i]; @@ -278,26 +268,34 @@ bool VoxelPacket::checkCompress() { _dirty = false; success = true; } + +//printf("checkCompress() returning %s _compressedBytes=%d\n",debug::valueOf(success), _compressedBytes); return success; } -void VoxelPacket::loadFinalizedContent(const unsigned char* data, int length) { - reset(); // by definition we reset upon loading compressed content - - if (length > 0) { +void VoxelPacketData::loadFinalizedContent(const unsigned char* data, int length) { + reset(); + + if (data && length > 0) { + if (_enableCompression) { QByteArray compressedData; + printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into compressedData \n", length); + for (int i = 0; i < length; i++) { compressedData[i] = data[i]; _compressed[i] = compressedData[i]; } _compressedBytes = length; - + + printf("VoxelPacketData::loadCompressedContent()... compressedData.size()=%d\n", compressedData.size()); QByteArray uncompressedData = qUncompress(compressedData); + printf("VoxelPacketData::loadCompressedContent()... uncompressedData.size()=%d\n", uncompressedData.size()); if (uncompressedData.size() <= _bytesAvailable) { + printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into _uncompressed[] \n", uncompressedData.size()); _bytesInUse = uncompressedData.size(); _bytesAvailable -= uncompressedData.size(); @@ -312,13 +310,13 @@ void VoxelPacket::loadFinalizedContent(const unsigned char* data, int length) { _bytesInUse = _compressedBytes = length; } } else { - if (_debug) printf("VoxelPacket::loadCompressedContent()... length = 0, nothing to do...\n"); + if (_debug) printf("VoxelPacketData::loadCompressedContent()... length = 0, nothing to do...\n"); } } -void VoxelPacket::debugContent() { +void VoxelPacketData::debugContent() { - printf("VoxelPacket::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes); + printf("VoxelPacketData::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes); int perline=0; for (int i = 0; i < _compressedBytes; i++) { printf("%.2x ",_compressed[i]); @@ -330,7 +328,7 @@ void VoxelPacket::debugContent() { } printf("\n"); - printf("VoxelPacket::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse); + printf("VoxelPacketData::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse); perline=0; for (int i = 0; i < _bytesInUse; i++) { printf("%.2x ",_uncompressed[i]); diff --git a/libraries/voxels/src/VoxelPacket.h b/libraries/voxels/src/VoxelPacketData.h similarity index 81% rename from libraries/voxels/src/VoxelPacket.h rename to libraries/voxels/src/VoxelPacketData.h index d6aafe597f..02ee2a6df5 100644 --- a/libraries/voxels/src/VoxelPacket.h +++ b/libraries/voxels/src/VoxelPacketData.h @@ -1,5 +1,5 @@ // -// VoxelPacket.h +// VoxelPacketData.h // hifi // // Created by Brad Hefta-Gaub on 11/19/2013 @@ -16,19 +16,26 @@ // to be recalculated // -#ifndef __hifi__VoxelPacket__ -#define __hifi__VoxelPacket__ +#ifndef __hifi__VoxelPacketData__ +#define __hifi__VoxelPacketData__ #include #include "VoxelConstants.h" #include "VoxelNode.h" -const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE - (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)); -const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = 4500; -const int VOXEL_PACKET_ALWAYS_TEST_COMPRESSED_THRESHOLD = 1400; -const int VOXEL_PACKET_TEST_UNCOMPRESSED_THRESHOLD = 4000; -const int VOXEL_PACKET_TEST_UNCOMPRESSED_CHANGE_THRESHOLD = 20; -const int VOXEL_PACKET_COMPRESSION_DEFAULT = false; +typedef unsigned char VOXEL_PACKET_FLAGS; +typedef uint16_t VOXEL_PACKET_SEQUENCE; +typedef uint64_t VOXEL_PACKET_SENT_TIME; +const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE; +const int VOXEL_PACKET_HEADER_SIZE = (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(VOXEL_PACKET_FLAGS) + + sizeof(VOXEL_PACKET_SEQUENCE) + sizeof(VOXEL_PACKET_SENT_TIME)); + +const int MAX_VOXEL_PACKET_DATA_SIZE = MAX_PACKET_SIZE - VOXEL_PACKET_HEADER_SIZE; + +const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_DATA_SIZE; + +const int PACKET_IS_COLOR_BIT = 0; +const int PACKET_IS_COMPRESSED_BIT = 1; class LevelDetails { LevelDetails(int startIndex, int bytesOfOctalCodes, int bytesOfBitmasks, int bytesOfColor) : @@ -38,7 +45,7 @@ class LevelDetails { _bytesOfColor(bytesOfColor) { } - friend class VoxelPacket; + friend class VoxelPacketData; private: int _startIndex; @@ -47,10 +54,13 @@ private: int _bytesOfColor; }; -class VoxelPacket { +class VoxelPacketData { public: - VoxelPacket(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_SIZE); - ~VoxelPacket(); + VoxelPacketData(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_DATA_SIZE); + ~VoxelPacketData(); + + /// change compression and target size settings + void changeSettings(bool enableCompression = false, int targetSize = MAX_VOXEL_PACKET_DATA_SIZE); /// reset completely, all data is discarded void reset(); @@ -108,6 +118,8 @@ public: /// load finalized content to allow access to decoded content for parsing void loadFinalizedContent(const unsigned char* data, int length); + + bool isCompressed() const { return _enableCompression; } void debugContent(); @@ -125,9 +137,9 @@ private: /// append a single byte, might fail if byte would cause packet to be too large bool append(unsigned char byte); + int _targetSize; bool _enableCompression; - int _maxFinalizedSize; - + unsigned char _uncompressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; int _bytesAvailable; @@ -150,4 +162,4 @@ private: }; -#endif /* defined(__hifi__VoxelPacket__) */ \ No newline at end of file +#endif /* defined(__hifi__VoxelPacketData__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelQuery.cpp b/libraries/voxels/src/VoxelQuery.cpp index ac39ea5c4c..1dc8eb0d8f 100644 --- a/libraries/voxels/src/VoxelQuery.cpp +++ b/libraries/voxels/src/VoxelQuery.cpp @@ -35,6 +35,7 @@ VoxelQuery::VoxelQuery(Node* owningNode) : _wantDelta(true), _wantLowResMoving(true), _wantOcclusionCulling(false), // disabled by default + _wantCompression(false), // disabled by default _maxVoxelPPS(DEFAULT_MAX_VOXEL_PPS), _voxelSizeScale(DEFAULT_VOXEL_SIZE_SCALE) { @@ -74,6 +75,7 @@ int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) { if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } + if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -122,10 +124,11 @@ int VoxelQuery::parseData(unsigned char* sourceBuffer, int numBytes) { // voxel sending features... unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; - _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); - _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); + _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); + _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); + _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); + _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Voxel PPS memcpy(&_maxVoxelPPS, sourceBuffer, sizeof(_maxVoxelPPS)); diff --git a/libraries/voxels/src/VoxelQuery.h b/libraries/voxels/src/VoxelQuery.h index c95b632eef..ed7814db09 100644 --- a/libraries/voxels/src/VoxelQuery.h +++ b/libraries/voxels/src/VoxelQuery.h @@ -28,7 +28,8 @@ const int WANT_LOW_RES_MOVING_BIT = 0; const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int WANT_OCCLUSION_CULLING_BIT = 3; // 4th bit +const int WANT_OCCLUSION_CULLING_BIT = 3; +const int WANT_COMPRESSION = 4; // 5th bit class VoxelQuery : public NodeData { Q_OBJECT @@ -68,6 +69,7 @@ public: bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } + bool getWantCompression() const { return _wantCompression; } int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPPS; } float getVoxelSizeScale() const { return _voxelSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } @@ -77,6 +79,7 @@ public slots: void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } + void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxVoxelPacketsPerSecond(int maxVoxelPPS) { _maxVoxelPPS = maxVoxelPPS; } void setVoxelSizeScale(float voxelSizeScale) { _voxelSizeScale = voxelSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -98,6 +101,7 @@ protected: bool _wantDelta; bool _wantLowResMoving; bool _wantOcclusionCulling; + bool _wantCompression; int _maxVoxelPPS; float _voxelSizeScale; /// used for LOD calculations int _boundaryLevelAdjust; /// used for LOD calculations diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2b9fb98082..b6107094e5 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1022,7 +1022,7 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& } int VoxelTree::encodeTreeBitstream(VoxelNode* node, - VoxelPacket* packet, VoxelNodeBag& bag, + VoxelPacketData* packetData, VoxelNodeBag& bag, EncodeBitstreamParams& params) { // How many bytes have we written so far at this level; @@ -1049,7 +1049,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, int codeLength; if (params.chopLevels) { unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); - roomForOctalCode = packet->startSubTree(newCode); + roomForOctalCode = packetData->startSubTree(newCode); if (newCode) { delete newCode; @@ -1057,7 +1057,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, codeLength = 1; } } else { - roomForOctalCode = packet->startSubTree(node->getOctalCode()); + roomForOctalCode = packetData->startSubTree(node->getOctalCode()); codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); } @@ -1079,7 +1079,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, packet, bag, params, currentEncodeLevel); + int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -1101,9 +1101,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } if (bytesWritten == 0) { - packet->discardSubTree(); + packetData->discardSubTree(); } else { - packet->endSubTree(); + packetData->endSubTree(); } doneEncoding(node); @@ -1112,7 +1112,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, } int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, - VoxelPacket* packet, VoxelNodeBag& bag, + VoxelPacketData* packetData, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1261,7 +1261,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const int BYTES_PER_COLOR = 3; // Make our local buffer large enough to handle writing at this level in case we need to. - LevelDetails thisLevelKey = packet->startLevel(); + LevelDetails thisLevelKey = packetData->startLevel(); int inViewCount = 0; int inViewNotLeafCount = 0; @@ -1440,7 +1440,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } bool continueThisLevel = true; - continueThisLevel = packet->appendBitMask(childrenColoredBits); + continueThisLevel = packetData->appendBitMask(childrenColoredBits); if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count @@ -1454,7 +1454,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { VoxelNode* childNode = node->getChildAtIndex(i); - continueThisLevel = packet->appendColor(childNode->getColor()); + continueThisLevel = packetData->appendColor(childNode->getColor()); if (!continueThisLevel) { break; // no point in continuing @@ -1474,7 +1474,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits if (continueThisLevel && params.includeExistsBits) { - continueThisLevel = packet->appendBitMask(childrenExistInTreeBits); + continueThisLevel = packetData->appendBitMask(childrenExistInTreeBits); if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count if (params.stats) { @@ -1485,7 +1485,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write the child exist bits if (continueThisLevel) { - continueThisLevel = packet->appendBitMask(childrenExistInPacketBits); + continueThisLevel = packetData->appendBitMask(childrenExistInPacketBits); if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count if (params.stats) { @@ -1508,7 +1508,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // write something, we keep them in the bits, if they don't, we take them out. // // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! - int childExistsPlaceHolder = packet->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); + int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, @@ -1516,7 +1516,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // a single recursive pass in distance sorted order, but retain standard order in our encoded packet int recursiveSliceSizes[NUMBER_OF_CHILDREN]; const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - int firstRecursiveSliceOffset = packet->getUncompressedByteOffset(); + int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); int allSlicesSize = 0; // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so @@ -1529,7 +1529,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, int thisLevel = currentEncodeLevel; // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packet->getUncompressedData() + packet->getUncompressedSize(); + recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); int childTreeBytesOut = 0; @@ -1542,8 +1542,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // // This only applies in the view frustum case, in other cases, like file save and copy/past where // no viewFrustum was requested, we still want to recurse the child tree. - if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { - childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packet, bag, params, thisLevel); + if (true || !params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { + childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, thisLevel); } // remember this for reshuffling @@ -1586,7 +1586,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, childrenExistInPacketBits -= (1 << (7 - originalIndex)); // repair the child exists mask - continueThisLevel = packet->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits); + continueThisLevel = packetData->updatePriorBitMask(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) { @@ -1622,7 +1622,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, } // now that all slices are back in the correct order, copy them to the correct output buffer - continueThisLevel = packet->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); + continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); } } // end keepDiggingDeeper @@ -1640,9 +1640,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // if we were unable to fit this level in our packet, then rewind and add it to the node bag for // sending later... if (continueThisLevel) { - continueThisLevel = packet->endLevel(thisLevelKey); + continueThisLevel = packetData->endLevel(thisLevelKey); } else { - packet->discardLevel(thisLevelKey); + packetData->discardLevel(thisLevelKey); } if (!continueThisLevel) { @@ -1861,7 +1861,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { nodeBag.insert(rootNode); } - static VoxelPacket packet; + static VoxelPacketData packetData; int bytesWritten = 0; bool lastPacketWritten = false; @@ -1870,17 +1870,17 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params); unlock(); // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet // and reinsert the node in our bag and try again... if (bytesWritten == 0) { - if (packet.hasContent()) { - file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); + if (packetData.hasContent()) { + file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); lastPacketWritten = true; } - packet.reset(); // is there a better way to do this? could we fit more? + packetData.reset(); // is there a better way to do this? could we fit more? nodeBag.insert(subTree); } else { lastPacketWritten = false; @@ -1888,7 +1888,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { } if (!lastPacketWritten) { - file.write((const char*)packet.getFinalizedData(), packet.getFinalizedSize()); + file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); } } @@ -1914,18 +1914,18 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); } - static VoxelPacket packet; + static VoxelPacketData packetData; int bytesWritten = 0; while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - packet.reset(); // reset the packet between usage + packetData.reset(); // reset the packet between usage // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); - bytesWritten = encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params); // ask destination tree to read the bitstream ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); - destinationTree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); + destinationTree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); } VoxelNode* destinationStartNode; @@ -1942,22 +1942,22 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); - static VoxelPacket packet; + static VoxelPacketData packetData; int bytesWritten = 0; while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - packet.reset(); // reset between usage + packetData.reset(); // reset between usage // ask our tree to write a bitsteam EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packet, nodeBag, params); + bytesWritten = sourceTree->encodeTreeBitstream(subTree, &packetData, nodeBag, params); // ask destination tree to read the bitstream bool wantImportProgress = true; ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress); - readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); + readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 29bfba28f9..6289a88d9d 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -17,7 +17,7 @@ #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" -#include "VoxelPacket.h" +#include "VoxelPacketData.h" #include "VoxelSceneStats.h" #include "VoxelEditPacketSender.h" @@ -198,7 +198,7 @@ public: void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData=NULL); - int encodeTreeBitstream(VoxelNode* node, VoxelPacket* packet, VoxelNodeBag& bag, + int encodeTreeBitstream(VoxelNode* node, VoxelPacketData* packetData, VoxelNodeBag& bag, EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } @@ -257,7 +257,7 @@ private: void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); int encodeTreeBitstreamRecursion(VoxelNode* node, - VoxelPacket* packet, VoxelNodeBag& bag, + VoxelPacketData* packetData, VoxelNodeBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel) const; static bool countVoxelsOperation(VoxelNode* node, void* extraData); From 2ce9937126bf31d31584914fcfd02c99145ab576 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 17:27:08 -0800 Subject: [PATCH 63/77] major pass on cleaning up voxel packets to have flags, sequence numbers, and flight time, add compression menu item --- interface/src/Application.cpp | 3 +- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/VoxelPacketProcessor.cpp | 2 +- interface/src/VoxelSystem.cpp | 83 +++++++++++--------------- 5 files changed, 40 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6005c455b6..e397f2846c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2579,6 +2579,7 @@ void Application::queryVoxels() { _voxelQuery.setWantColor(!Menu::getInstance()->isOptionChecked(MenuOption::DisableColorVoxels)); _voxelQuery.setWantDelta(!Menu::getInstance()->isOptionChecked(MenuOption::DisableDeltaSending)); _voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::EnableOcclusionCulling)); + _voxelQuery.setWantCompression(Menu::getInstance()->isOptionChecked(MenuOption::EnableVoxelPacketCompression)); _voxelQuery.setCameraPosition(_viewFrustum.getPosition()); _voxelQuery.setCameraOrientation(_viewFrustum.getOrientation()); @@ -4395,8 +4396,6 @@ void* Application::networkReceive(void* args) { app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived); break; case PACKET_TYPE_VOXEL_DATA: - case PACKET_TYPE_VOXEL_DATA_MONOCHROME: - case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: case PACKET_TYPE_VOXEL_STATS: case PACKET_TYPE_ENVIRONMENT_DATA: { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ca3d72ed8f..8cc49e701e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -303,6 +303,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableColorVoxels); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableLowRes); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableDeltaSending); + addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableVoxelPacketCompression); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableOcclusionCulling); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3696cb4cff..7e04e931d9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -171,6 +171,7 @@ namespace MenuOption { const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels"; const QString EchoAudio = "Echo Audio"; const QString EnableOcclusionCulling = "Enable Occlusion Culling"; + const QString EnableVoxelPacketCompression = "Enable Voxel Packet Compression"; const QString ExportVoxels = "Export Voxels"; const QString ExtraDebugging = "Extra Debugging"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 9087a5a545..5917e2fb05 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -32,7 +32,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* app->_wantToKillLocalVoxels = false; } - // note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME + // note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA // 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 (packetData[0] == PACKET_TYPE_VOXEL_STATS) { diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9e82c61351..d2c32d5ab7 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -595,62 +595,51 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char command = *sourceBuffer; int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer); - unsigned char* voxelData = sourceBuffer + numBytesPacketHeader; - switch(command) { case PACKET_TYPE_VOXEL_DATA: { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); + + unsigned char* dataAt = sourceBuffer + numBytesPacketHeader; + + VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); + dataAt += sizeof(VOXEL_PACKET_FLAGS); + VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + + VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SENT_TIME); + + unsigned char* voxelData = dataAt; + + bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); + bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); + + VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); + int flightTime = arrivedAt - sentAt; + + int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; + if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + printf("Got Packet... color:%s compressed:%s sequence: %u flightTime:%d size:%d data:%d\n", + debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), + sequence, flightTime, numBytes, dataBytes); + } + // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); + + // need to check for WANT_COLOR vs NO_COLOR + // need to also setup packet properly with enableCompression true/false + ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); - VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); - int compressedSize = numBytes - numBytesPacketHeader; - packet.loadFinalizedContent(voxelData, compressedSize); - if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); + VoxelPacketData packetData(packetIsCompressed); + packetData.loadFinalizedContent(voxelData, dataBytes); + if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n", + numBytes, dataBytes, packetData.getUncompressedSize()); } - _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); + _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); unlockTree(); } - break; - case PACKET_TYPE_VOXEL_DATA_MONOCHROME: { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "readBitstreamToTree()"); - // ask the VoxelTree to read the MONOCHROME bitstream into the tree - ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - lockTree(); - VoxelPacket packet(VOXEL_PACKET_COMPRESSION_DEFAULT); - int compressedSize = numBytes - numBytesPacketHeader; - packet.loadFinalizedContent(voxelData, compressedSize); - if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n",numBytes, compressedSize, packet.getUncompressedSize()); - } - _tree->readBitstreamToTree(packet.getUncompressedData(), packet.getUncompressedSize(), args); - unlockTree(); - } - break; - case PACKET_TYPE_Z_COMMAND: - - // the Z command is a special command that allows the sender to send high level semantic - // requests, like erase all, or add sphere scene, different receivers may handle these - // messages differently - char* packetData = (char *)sourceBuffer; - char* command = &packetData[numBytesPacketHeader]; // start of the command - int commandLength = strlen(command); // commands are null terminated strings - int totalLength = 1+commandLength+1; - - qDebug("got Z message len(%d)= %s\n", numBytes, command); - - while (totalLength <= numBytes) { - if (0==strcmp(command,(char*)"erase all")) { - qDebug("got Z message == erase all - NOT SUPPORTED ON INTERFACE\n"); - } - if (0==strcmp(command,(char*)"add scene")) { - qDebug("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); - } - totalLength += commandLength+1; - } break; } From 77590b5b8781d8f14e50a752a2e4603379e71a39 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 19:23:21 -0800 Subject: [PATCH 64/77] cleanup debug, readd fix to not recurse subtrees when node is colored --- interface/src/VoxelSystem.cpp | 17 ++++------- .../src/VoxelSendThread.cpp | 29 +++++++------------ libraries/voxels/src/VoxelPacketData.cpp | 16 ++-------- libraries/voxels/src/VoxelTree.cpp | 2 +- 4 files changed, 19 insertions(+), 45 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index d2c32d5ab7..322e20aa44 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -619,23 +619,16 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { int flightTime = arrivedAt - sentAt; int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; - if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - printf("Got Packet... color:%s compressed:%s sequence: %u flightTime:%d size:%d data:%d\n", - debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, numBytes, dataBytes); - } - + // ask the VoxelTree to read the bitstream into the tree - - // need to check for WANT_COLOR vs NO_COLOR - // need to also setup packet properly with enableCompression true/false ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); VoxelPacketData packetData(packetIsCompressed); packetData.loadFinalizedContent(voxelData, dataBytes); - if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("got packet numBytes=%d finalized size %d uncompressed size %d\n", - numBytes, dataBytes, packetData.getUncompressedSize()); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d uncompressed:%d\n", + debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), + sequence, flightTime, numBytes, dataBytes, packetData.getUncompressedSize()); } _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); unlockTree(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 889834b183..28f57d7d4a 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -97,7 +97,7 @@ uint64_t VoxelSendThread::_totalWastedBytes = 0; uint64_t VoxelSendThread::_totalPackets = 0; int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = true; // _myServer->wantsDebugVoxelSending(); + bool debug = _myServer->wantsDebugVoxelSending(); uint64_t now = usecTimestampNow(); bool packetSent = false; // did we send a packet? @@ -254,7 +254,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _packetData.changeSettings(wantCompression); } - if (true || (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug())) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), @@ -313,15 +313,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - bool debug = false; - if (debug) { - qDebug() << "Scene completed at " << usecTimestampNow() << - " encodeTime: "<< encodeTime << - " sleepTime: " << sleepTime << - " elapsed: "<< elapsedTime << - " Packets:["<< _totalPackets <<"]"<< - " Total Bytes:["<< _totalBytes <<"]"<< - " Wasted bytes:["<< _totalWastedBytes << "]\n"; + if (true || _myServer->wantsDebugVoxelSending()) { + qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", + usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); } } @@ -339,16 +333,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->nodeBag.deleteAll(); } - bool debug = false; - if (debug) { - qDebug() << "Scene started at " << usecTimestampNow() << - " Packets:["<< _totalPackets <<"]"<< - " Total Bytes:["<< _totalBytes <<"]"<< - " Wasted bytes:["<< _totalWastedBytes << "]\n"; + if (_myServer->wantsDebugVoxelSending()) { + qDebug("Scene started at %llu Packets:%llu Bytes:%llu Wasted:%llu\n", + usecTimestampNow(),_totalPackets,_totalBytes,_totalWastedBytes); } ::startSceneSleepTime = _usleepTime; - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, + _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); // This is the start of "resending" the scene. bool dontRestartSceneOnMove = false; // this is experimental @@ -479,7 +471,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } } else if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } diff --git a/libraries/voxels/src/VoxelPacketData.cpp b/libraries/voxels/src/VoxelPacketData.cpp index c403e582f1..dbbfa0da2e 100644 --- a/libraries/voxels/src/VoxelPacketData.cpp +++ b/libraries/voxels/src/VoxelPacketData.cpp @@ -128,9 +128,6 @@ const unsigned char* VoxelPacketData::getFinalizedData() { } checkCompress(); } - -printf("VoxelPacketData::getFinalizedData()... _bytesInUse=%d compressed version..._compressedBytes=%d\n",_bytesInUse, _compressedBytes); - return &_compressed[0]; } @@ -281,21 +278,13 @@ void VoxelPacketData::loadFinalizedContent(const unsigned char* data, int length if (_enableCompression) { QByteArray compressedData; - - printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into compressedData \n", length); - for (int i = 0; i < length; i++) { compressedData[i] = data[i]; _compressed[i] = compressedData[i]; } _compressedBytes = length; - - printf("VoxelPacketData::loadCompressedContent()... compressedData.size()=%d\n", compressedData.size()); QByteArray uncompressedData = qUncompress(compressedData); - printf("VoxelPacketData::loadCompressedContent()... uncompressedData.size()=%d\n", uncompressedData.size()); - if (uncompressedData.size() <= _bytesAvailable) { - printf("VoxelPacketData::loadCompressedContent()... copying %d bytes into _uncompressed[] \n", uncompressedData.size()); _bytesInUse = uncompressedData.size(); _bytesAvailable -= uncompressedData.size(); @@ -310,12 +299,13 @@ void VoxelPacketData::loadFinalizedContent(const unsigned char* data, int length _bytesInUse = _compressedBytes = length; } } else { - if (_debug) printf("VoxelPacketData::loadCompressedContent()... length = 0, nothing to do...\n"); + if (_debug) { + printf("VoxelPacketData::loadCompressedContent()... length = 0, nothing to do...\n"); + } } } void VoxelPacketData::debugContent() { - printf("VoxelPacketData::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes); int perline=0; for (int i = 0; i < _compressedBytes; i++) { diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b6107094e5..450f784765 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1542,7 +1542,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, // // This only applies in the view frustum case, in other cases, like file save and copy/past where // no viewFrustum was requested, we still want to recurse the child tree. - if (true || !params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { + if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, thisLevel); } From b7ee2ea2db86326f8a74a298c434bf5eef52efa1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 19:47:14 -0800 Subject: [PATCH 65/77] add section size to compressed packets to allow packing of multiple sections --- interface/src/VoxelSystem.cpp | 19 +++++++++++++------ .../src/VoxelNodeData.cpp | 7 +++++++ .../src/VoxelSendThread.cpp | 4 +++- libraries/voxels/src/VoxelPacketData.h | 1 + 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 322e20aa44..a52429542f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -610,25 +610,32 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); dataAt += sizeof(VOXEL_PACKET_SENT_TIME); - unsigned char* voxelData = dataAt; - bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); int flightTime = arrivedAt - sentAt; + VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; + + if (packetIsCompressed && dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { + sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + } else { + sectionLength = dataBytes; + } + unsigned char* voxelData = dataAt; // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); lockTree(); VoxelPacketData packetData(packetIsCompressed); - packetData.loadFinalizedContent(voxelData, dataBytes); - if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d uncompressed:%d\n", + packetData.loadFinalizedContent(voxelData, sectionLength); + if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d sectionLength:%d uncompressed:%d\n", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, numBytes, dataBytes, packetData.getUncompressedSize()); + sequence, flightTime, numBytes, dataBytes, sectionLength, packetData.getUncompressedSize()); } _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); unlockTree(); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 8068c57bcc..5509fa1200 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -133,6 +133,13 @@ void VoxelNodeData::resetVoxelPacket() { } void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { + // compressed packets include lead bytes which contain compressed size, this allows packing of + // multiple compressed portions together + if (_currentPacketIsCompressed) { + *(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)_voxelPacketAt = bytes; + _voxelPacketAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + } memcpy(_voxelPacketAt, buffer, bytes); _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 28f57d7d4a..93cf80905f 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -251,7 +251,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } nodeData->resetVoxelPacket(); } - _packetData.changeSettings(wantCompression); + int uncompressedSize = !wantCompression ? MAX_VOXEL_PACKET_DATA_SIZE + : MAX_VOXEL_PACKET_DATA_SIZE - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + _packetData.changeSettings(wantCompression, uncompressedSize); } if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { diff --git a/libraries/voxels/src/VoxelPacketData.h b/libraries/voxels/src/VoxelPacketData.h index 02ee2a6df5..8dab8c2290 100644 --- a/libraries/voxels/src/VoxelPacketData.h +++ b/libraries/voxels/src/VoxelPacketData.h @@ -26,6 +26,7 @@ typedef unsigned char VOXEL_PACKET_FLAGS; typedef uint16_t VOXEL_PACKET_SEQUENCE; typedef uint64_t VOXEL_PACKET_SENT_TIME; +typedef uint16_t VOXEL_PACKET_INTERNAL_SECTION_SIZE; const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE; const int VOXEL_PACKET_HEADER_SIZE = (sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(VOXEL_PACKET_FLAGS) + sizeof(VOXEL_PACKET_SEQUENCE) + sizeof(VOXEL_PACKET_SENT_TIME)); From dac211cebdc4247f2a555510e5ee230b5bce4f55 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 22:18:24 -0800 Subject: [PATCH 66/77] pack more compressed sections into wire packets if there is room --- interface/src/VoxelSystem.cpp | 53 ++++++---- .../src/VoxelNodeData.cpp | 14 ++- .../voxel-server-library/src/VoxelNodeData.h | 2 +- .../src/VoxelSendThread.cpp | 96 ++++++++++++++++--- libraries/voxels/src/VoxelPacketData.cpp | 6 +- libraries/voxels/src/VoxelPacketData.h | 5 + 6 files changed, 133 insertions(+), 43 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a52429542f..324f293110 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -619,26 +619,41 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; - if (packetIsCompressed && dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { - sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); - dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); - } else { - sectionLength = dataBytes; + int subsection = 1; + while (dataBytes > 0) { + if (packetIsCompressed) { + if (dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { + sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + dataBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + } else { + sectionLength = 0; + dataBytes = 0; // stop looping something is wrong + } + } else { + sectionLength = dataBytes; + } + + if (sectionLength) { + // ask the VoxelTree to read the bitstream into the tree + ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); + lockTree(); + VoxelPacketData packetData(packetIsCompressed); + packetData.loadFinalizedContent(dataAt, sectionLength); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" + " subsection:%d sectionLength:%d uncompressed:%d\n", + debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), + sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize()); + } + _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); + unlockTree(); + + dataBytes -= sectionLength; + dataAt += sectionLength; + } } - unsigned char* voxelData = dataAt; - - // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - lockTree(); - VoxelPacketData packetData(packetIsCompressed); - packetData.loadFinalizedContent(voxelData, sectionLength); - if (true || Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d sectionLength:%d uncompressed:%d\n", - debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, numBytes, dataBytes, sectionLength, packetData.getUncompressedSize()); - } - _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); - unlockTree(); + subsection++; } break; } diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 5509fa1200..6c18effa54 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -16,7 +16,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelQuery(owningNode), _viewSent(false), - _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), + _voxelPacketAvailableBytes(MAX_PACKET_SIZE), _maxSearchLevel(1), _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), @@ -30,9 +30,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lodChanged(false), _lodInitialized(false) { - _voxelPacket = new unsigned char[_voxelPacketAvailableBytes]; + _voxelPacket = new unsigned char[MAX_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; - _lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; + _lastVoxelPacket = new unsigned char[MAX_PACKET_SIZE]; _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; _sequenceNumber = 0; @@ -108,18 +108,22 @@ void VoxelNodeData::resetVoxelPacket() { setAtBit(flags,PACKET_IS_COMPRESSED_BIT); } + _voxelPacketAvailableBytes = MAX_PACKET_SIZE; int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; + _voxelPacketAvailableBytes -= numBytesPacketHeader; // pack in flags VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt; *flagsAt = flags; _voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS); + _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_FLAGS); // pack in sequence number VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt; *sequenceAt = _sequenceNumber; _voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE); + _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SEQUENCE); _sequenceNumber++; // pack in timestamp @@ -127,8 +131,8 @@ void VoxelNodeData::resetVoxelPacket() { VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt; *timeAt = now; _voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME); + _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SENT_TIME); - _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_DATA_SIZE; _voxelPacketWaiting = false; } @@ -144,6 +148,8 @@ void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { _voxelPacketAvailableBytes -= bytes; _voxelPacketAt += bytes; _voxelPacketWaiting = true; + + assert(_voxelPacketAvailableBytes >= 0); } VoxelNodeData::~VoxelNodeData() { diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index bc6409b10c..fa0adc9e44 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -32,7 +32,7 @@ public: void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet const unsigned char* getPacket() const { return _voxelPacket; } - int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } + int getPacketLength() const { return (MAX_PACKET_SIZE - _voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } bool packetIsDuplicate() const; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 93cf80905f..001e7005ac 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -251,9 +251,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } nodeData->resetVoxelPacket(); } - int uncompressedSize = !wantCompression ? MAX_VOXEL_PACKET_DATA_SIZE - : MAX_VOXEL_PACKET_DATA_SIZE - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); - _packetData.changeSettings(wantCompression, uncompressedSize); + int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + } + printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, + debug::valueOf(wantCompression), targetSize); + + _packetData.changeSettings(wantCompression, targetSize); } if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { @@ -315,7 +320,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - if (true || _myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending()) { qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); } @@ -373,6 +378,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); } + int extraPackingAttempts = 0; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", @@ -407,8 +413,20 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->stats.encodeStarted(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); - if (_packetData.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { - lastNodeDidntFit = true; + // if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case. + if (_packetData.getTargetSize() == MAX_VOXEL_PACKET_DATA_SIZE) { + if (_packetData.hasContent() && bytesWritten == 0 && + params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { + lastNodeDidntFit = true; + } + } else { + // in compressed mode and we are trying to pack more... and we don't care if the _packetData has + // content or not... because in this case even if we were unable to pack any data, we want to drop + // below to our sendNow logic, but we do want to track that we attempted to pack extra + extraPackingAttempts++; + if (bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { + lastNodeDidntFit = true; + } } if (bytesWritten > 0) { @@ -422,18 +440,68 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod somethingToSend = false; // this will cause us to drop out of the loop... } + // If the last node didn't fit, but we're in compressed mode, then we actually want to see if we can fit a + // little bit more in this packet. To do this we + // We only consider sending anything if there is something in the _packetData to send... But // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases // mean we should send the previous packet contents and reset it. - bool sendNow = lastNodeDidntFit; - if (_packetData.hasContent() && sendNow) { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", - _packetData.getFinalizedSize(), _packetData.getUncompressedSize()); + if (lastNodeDidntFit) { + if (_packetData.hasContent()) { + // if for some reason the finalized size is greater than our available size, then probably the "compressed" + // form actually inflated beyond our padding, and in this case we will send the current packet, then + // write to out new packet... + int writtenSize = _packetData.getFinalizedSize() + + (nodeData->getCurrentPacketIsCompressed() ? sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) : 0); + + + if (writtenSize > nodeData->getAvailable()) { + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + printf("writtenSize[%d] > available[%d] too big, sending packet as is.\n", + writtenSize, nodeData->getAvailable()); + } + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + } + + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + printf("calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n", + nodeData->getAvailable(), _packetData.getFinalizedSize(), + _packetData.getUncompressedSize(), _packetData.getTargetSize()); + } + nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); + extraPackingAttempts = 0; } - nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - _packetData.reset(); + + // If we're not running compressed, the we know we can just send now. Or if we're running compressed, but + // the packet doesn't have enough space to bother attempting to pack more... + bool sendNow = true; + + if (nodeData->getCurrentPacketIsCompressed() && + nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && + extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) { + sendNow = false; // try to pack more + } + + int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; + if (sendNow) { + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + } + } else { + // If we're in compressed mode, then we want to see if we have room for more in this wire packet. + // but we've finalized the _packetData, so we want to start a new section, we will do that by + // resetting the packet settings with the max uncompressed size of our current available space + // in the wire packet. We also include room for our section header, and a little bit of padding + // to account for the fact that whenc compressing small amounts of data, we sometimes end up with + // a larger compressed size then uncompressed size + targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; + } + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, + debug::valueOf(nodeData->getWantCompression()), targetSize); + } + _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset } } diff --git a/libraries/voxels/src/VoxelPacketData.cpp b/libraries/voxels/src/VoxelPacketData.cpp index dbbfa0da2e..d9efc648d8 100644 --- a/libraries/voxels/src/VoxelPacketData.cpp +++ b/libraries/voxels/src/VoxelPacketData.cpp @@ -28,11 +28,7 @@ void VoxelPacketData::changeSettings(bool enableCompression, int targetSize) { void VoxelPacketData::reset() { _bytesInUse = 0; - if (_enableCompression) { - _bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE; - } else { - _bytesAvailable = _targetSize; - } + _bytesAvailable = _targetSize; _subTreeAt = 0; _compressedBytes = 0; _bytesInUseLastCheck = 0; diff --git a/libraries/voxels/src/VoxelPacketData.h b/libraries/voxels/src/VoxelPacketData.h index 8dab8c2290..b443556de3 100644 --- a/libraries/voxels/src/VoxelPacketData.h +++ b/libraries/voxels/src/VoxelPacketData.h @@ -35,6 +35,10 @@ const int MAX_VOXEL_PACKET_DATA_SIZE = MAX_PACKET_SIZE - VOXEL_PACKET_HEADER_SIZ const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_DATA_SIZE; +const int MINIMUM_ATTEMPT_MORE_PACKING = sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) + 40; +const int COMPRESS_PADDING = 15; +const int REASONABLE_NUMBER_OF_PACKING_ATTEMPTS = 5; + const int PACKET_IS_COLOR_BIT = 0; const int PACKET_IS_COMPRESSED_BIT = 1; @@ -121,6 +125,7 @@ public: void loadFinalizedContent(const unsigned char* data, int length); bool isCompressed() const { return _enableCompression; } + int getTargetSize() const { return _targetSize; } void debugContent(); From 77636678a8af1669b48adb4ec95c93080e2c3522 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 22:27:48 -0800 Subject: [PATCH 67/77] moved debug into if --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 001e7005ac..311379cf52 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -255,8 +255,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (wantCompression) { targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); } - printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, - debug::valueOf(wantCompression), targetSize); + if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, + debug::valueOf(wantCompression), targetSize); + } _packetData.changeSettings(wantCompression, targetSize); } From 3a16a4935d30fee56d23cf2cdc1a6b4e32e6d4cc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 26 Nov 2013 22:43:49 -0800 Subject: [PATCH 68/77] added additional flight time debugging --- interface/src/Application.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e397f2846c..3fc5cfb0a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4401,6 +4401,21 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_ENVIRONMENT_DATA: { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); + + bool wantExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); + if (wantExtraDebugging && app->_incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) { + int numBytesPacketHeader = numBytesForPacketHeader(app->_incomingPacket); + unsigned char* dataAt = app->_incomingPacket + numBytesPacketHeader; + dataAt += sizeof(VOXEL_PACKET_FLAGS); + VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SENT_TIME); + VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); + int flightTime = arrivedAt - sentAt; + + printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime); + } // add this packet to our list of voxel packets and process them on the voxel processing app->_voxelProcessor.queueReceivedPacket(senderAddress, app->_incomingPacket, bytesReceived); From 7cc5339702ddda9ff3bf03283c3bf8f45ada9cf2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 07:40:23 -0800 Subject: [PATCH 69/77] cleanup comments and coding standard --- .../src/VoxelSendThread.cpp | 8 ++--- .../voxel-server-library/src/VoxelServer.cpp | 6 ++-- libraries/voxels/src/VoxelPacketData.cpp | 15 ++++------ libraries/voxels/src/VoxelPacketData.h | 29 +++++++++++++------ 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 311379cf52..918d23fd55 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -366,8 +366,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; uint64_t start = usecTimestampNow(); - uint64_t startCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000; - uint64_t startCompressCalls = VoxelPacketData::_checkCompressCalls; + uint64_t startCompressTimeMsecs = VoxelPacketData::getCompressContentTime() / 1000; + uint64_t startCompressCalls = VoxelPacketData::getCompressContentCalls(); bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); @@ -526,10 +526,10 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start)/1000; - uint64_t endCompressCalls = VoxelPacketData::_checkCompressCalls; + uint64_t endCompressCalls = VoxelPacketData::getCompressContentCalls(); int elapsedCompressCalls = endCompressCalls - startCompressCalls; - uint64_t endCompressTimeMsecs = VoxelPacketData::_checkCompressTime / 1000; + uint64_t endCompressTimeMsecs = VoxelPacketData::getCompressContentTime() / 1000; int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index d0c2a5bca5..4f0bf1185e 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -268,9 +268,9 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { uint64_t totalOutboundPackets = VoxelSendThread::_totalPackets; uint64_t totalOutboundBytes = VoxelSendThread::_totalBytes; uint64_t totalWastedBytes = VoxelSendThread::_totalWastedBytes; - uint64_t totalBytesOfOctalCodes = VoxelPacketData::_totalBytesOfOctalCodes; - uint64_t totalBytesOfBitMasks = VoxelPacketData::_totalBytesOfBitMasks; - uint64_t totalBytesOfColor = VoxelPacketData::_totalBytesOfColor; + uint64_t totalBytesOfOctalCodes = VoxelPacketData::getTotalBytesOfOctalCodes(); + uint64_t totalBytesOfBitMasks = VoxelPacketData::getTotalBytesOfBitMasks(); + uint64_t totalBytesOfColor = VoxelPacketData::getTotalBytesOfColor(); const int COLUMN_WIDTH = 10; mg_printf(connection, " Total Outbound Packets: %s packets\r\n", diff --git a/libraries/voxels/src/VoxelPacketData.cpp b/libraries/voxels/src/VoxelPacketData.cpp index d9efc648d8..e5c169881e 100644 --- a/libraries/voxels/src/VoxelPacketData.cpp +++ b/libraries/voxels/src/VoxelPacketData.cpp @@ -117,12 +117,11 @@ const unsigned char* VoxelPacketData::getFinalizedData() { return &_uncompressed[0]; } - if (_dirty) { if (_debug) { printf("getFinalizedData() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); } - checkCompress(); + compressContent(); } return &_compressed[0]; } @@ -136,7 +135,7 @@ int VoxelPacketData::getFinalizedSize() { if (_debug) { printf("getFinalizedSize() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse); } - checkCompress(); + compressContent(); } return _compressedBytes; @@ -231,11 +230,11 @@ bool VoxelPacketData::appendColor(const nodeColor& color) { return success; } -uint64_t VoxelPacketData::_checkCompressTime = 0; -uint64_t VoxelPacketData::_checkCompressCalls = 0; +uint64_t VoxelPacketData::_compressContentTime = 0; +uint64_t VoxelPacketData::_compressContentCalls = 0; -bool VoxelPacketData::checkCompress() { - PerformanceWarning warn(false,"VoxelPacketData::checkCompress()",false,&_checkCompressTime,&_checkCompressCalls); +bool VoxelPacketData::compressContent() { + PerformanceWarning warn(false, "VoxelPacketData::compressContent()", false, &_compressContentTime, &_compressContentCalls); // without compression, we always pass... if (!_enableCompression) { @@ -261,8 +260,6 @@ bool VoxelPacketData::checkCompress() { _dirty = false; success = true; } - -//printf("checkCompress() returning %s _compressedBytes=%d\n",debug::valueOf(success), _compressedBytes); return success; } diff --git a/libraries/voxels/src/VoxelPacketData.h b/libraries/voxels/src/VoxelPacketData.h index b443556de3..8dbcef29a0 100644 --- a/libraries/voxels/src/VoxelPacketData.h +++ b/libraries/voxels/src/VoxelPacketData.h @@ -42,6 +42,7 @@ const int REASONABLE_NUMBER_OF_PACKING_ATTEMPTS = 5; const int PACKET_IS_COLOR_BIT = 0; const int PACKET_IS_COMPRESSED_BIT = 1; +/// An opaque key used when starting, ending, and discarding encoding/packing levels of VoxelPacketData class LevelDetails { LevelDetails(int startIndex, int bytesOfOctalCodes, int bytesOfBitmasks, int bytesOfColor) : _startIndex(startIndex), @@ -59,6 +60,7 @@ private: int _bytesOfColor; }; +/// Handles packing of the data portion of PACKET_TYPE_VOXEL_DATA messages. class VoxelPacketData { public: VoxelPacketData(bool enableCompression = false, int maxFinalizedSize = MAX_VOXEL_PACKET_DATA_SIZE); @@ -124,18 +126,21 @@ public: /// load finalized content to allow access to decoded content for parsing void loadFinalizedContent(const unsigned char* data, int length); + /// returns whether or not zlib compression enabled on finalization bool isCompressed() const { return _enableCompression; } + + /// returns the target uncompressed size int getTargetSize() const { return _targetSize; } + /// displays contents for debugging void debugContent(); + + static uint64_t getCompressContentTime() { return _compressContentTime; } /// total time spent compressing content + static uint64_t getCompressContentCalls() { return _compressContentCalls; } /// total calls to compress content + static uint64_t getTotalBytesOfOctalCodes() { return _totalBytesOfOctalCodes; } /// total bytes for octal codes + static uint64_t getTotalBytesOfBitMasks() { return _totalBytesOfBitMasks; } /// total bytes of bitmasks + static uint64_t getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color - static uint64_t _checkCompressTime; - static uint64_t _checkCompressCalls; - - static uint64_t _totalBytesOfOctalCodes; - static uint64_t _totalBytesOfBitMasks; - static uint64_t _totalBytesOfColor; - private: /// appends raw bytes, might fail if byte would cause packet to be too large bool append(const unsigned char* data, int length); @@ -151,7 +156,7 @@ private: int _bytesAvailable; int _subTreeAt; - bool checkCompress(); + bool compressContent(); unsigned char _compressed[MAX_VOXEL_UNCOMRESSED_PACKET_SIZE]; int _compressedBytes; @@ -165,7 +170,13 @@ private: int _bytesOfOctalCodesCurrentSubTree; static bool _debug; - + + static uint64_t _compressContentTime; + static uint64_t _compressContentCalls; + + static uint64_t _totalBytesOfOctalCodes; + static uint64_t _totalBytesOfBitMasks; + static uint64_t _totalBytesOfColor; }; #endif /* defined(__hifi__VoxelPacketData__) */ \ No newline at end of file From e389c5daa1aea065966a4eedbd0cd0fd87b8f1ce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 08:25:24 -0800 Subject: [PATCH 70/77] adding additional per server voxel stats --- interface/src/ui/VoxelStatsDialog.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index ff082e4b02..04226c36f8 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -208,6 +208,8 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) { } void VoxelStatsDialog::showAllVoxelServers() { + QLocale locale(QLocale::English); + int serverNumber = 0; int serverCount = 0; NodeList* nodeList = NodeList::getInstance(); @@ -265,8 +267,26 @@ void VoxelStatsDialog::showAllVoxelServers() { } // root code } // jurisdiction + // now lookup stats details for this server... + Application::getInstance()->lockVoxelSceneStats(); + NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats(); + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + VoxelSceneStats& stats = sceneStats->at(nodeUUID); + + QString totalString = locale.toString((uint)stats.getTotalVoxels()); + QString internalString = locale.toString((uint)stats.getTotalInternal()); + QString leavesString = locale.toString((uint)stats.getTotalLeaves()); + + serverDetails << "\n" << "Nodes:" << + totalString.toLocal8Bit().constData() << " total " << + internalString.toLocal8Bit().constData() << " internal " << + leavesString.toLocal8Bit().constData() << " leaves "; + } + Application::getInstance()->unlockVoxelSceneStats(); + _labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); + } // is VOXEL_SERVER } // Node Loop From 17e979dc9fb7927b09e67b2b509b721c9ad5d49a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 10:20:49 -0800 Subject: [PATCH 71/77] improved client side stats, don't suppress initial stats message in server since it includes jurisdiction --- interface/src/ui/VoxelStatsDialog.cpp | 48 ++++++++++++------- interface/src/ui/VoxelStatsDialog.h | 2 +- .../src/VoxelSendThread.cpp | 32 +++++-------- .../src/VoxelSendThread.h | 2 - libraries/voxels/src/VoxelSceneStats.cpp | 17 +++++++ libraries/voxels/src/VoxelSceneStats.h | 5 ++ 6 files changed, 68 insertions(+), 38 deletions(-) diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index 04226c36f8..05cd3cf6b7 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -40,20 +40,11 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model this->QDialog::setLayout(_form); // Setup stat items - _serverVoxels = AddStatItem("Voxels on Servers", GREENISH); - _localVoxels = AddStatItem("Local Voxels", YELLOWISH); - _localVoxelsMemory = AddStatItem("Voxels Memory", GREYISH); - _voxelsRendered = AddStatItem("Voxels Rendered", GREENISH); - _sendingMode = AddStatItem("Sending Mode", YELLOWISH); - - /** NOT YET READY - VoxelSceneStats temp; - for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { - VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); - VoxelSceneStats::ItemInfo& itemInfo = temp.getItemInfo(item); - AddStatItem(itemInfo.caption, itemInfo.colorRGBA); - } - **/ + _serverVoxels = AddStatItem("Voxels on Servers"); + _localVoxels = AddStatItem("Local Voxels"); + _localVoxelsMemory = AddStatItem("Voxels Memory"); + _voxelsRendered = AddStatItem("Voxels Rendered"); + _sendingMode = AddStatItem("Sending Mode"); } void VoxelStatsDialog::RemoveStatItem(int item) { @@ -71,6 +62,11 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { const int STATS_LABEL_WIDTH = 900; _statCount++; // increment our current stat count + + if (colorRGBA == 0) { + static unsigned rotatingColors[] = { GREENISH, YELLOWISH, GREYISH }; + colorRGBA = rotatingColors[_statCount % (sizeof(rotatingColors)/sizeof(rotatingColors[0]))]; + } QLabel* label = _labels[_statCount] = new QLabel(); @@ -222,7 +218,7 @@ void VoxelStatsDialog::showAllVoxelServers() { if (serverCount > _voxelServerLabelsCount) { char label[128] = { 0 }; sprintf(label, "Voxel Server %d",serverCount); - _voxelServerLables[serverCount-1] = AddStatItem(label, GREENISH); + _voxelServerLables[serverCount-1] = AddStatItem(label); _voxelServerLabelsCount++; } @@ -277,10 +273,30 @@ void VoxelStatsDialog::showAllVoxelServers() { QString internalString = locale.toString((uint)stats.getTotalInternal()); QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - serverDetails << "\n" << "Nodes:" << + serverDetails << "\n" << "Voxels: " << totalString.toLocal8Bit().constData() << " total " << internalString.toLocal8Bit().constData() << " internal " << leavesString.toLocal8Bit().constData() << " leaves "; + + const unsigned long USECS_PER_MSEC = 1000; + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + + QString lastFullEncodeString = locale.toString(lastFullEncode); + QString lastFullSendString = locale.toString(lastFullSend); + + serverDetails << "\n" << "Last Full Scene... " << + "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << + "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; + + bool details = false; // for now, we'd like to add an expand/contract feature to each voxel server + if (details) { + for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { + VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); + VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + serverDetails << "\n" << itemInfo.caption << " " << stats.getItemValue(item); + } + } } Application::getInstance()->unlockVoxelSceneStats(); diff --git a/interface/src/ui/VoxelStatsDialog.h b/interface/src/ui/VoxelStatsDialog.h index cee6c47a11..2099d5b122 100644 --- a/interface/src/ui/VoxelStatsDialog.h +++ b/interface/src/ui/VoxelStatsDialog.h @@ -38,7 +38,7 @@ protected: // Emits a 'closed' signal when this dialog is closed. void closeEvent(QCloseEvent*); - int AddStatItem(const char* caption, unsigned colorRGBA); + int AddStatItem(const char* caption, unsigned colorRGBA = 0); void RemoveStatItem(int item); void showAllVoxelServers(); diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 918d23fd55..8c84b924c1 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -29,8 +29,7 @@ uint64_t endSceneSleepTime = 0; VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : _nodeUUID(nodeUUID), _myServer(myServer), - _packetData(), - _encodedSomething(false) + _packetData() { } @@ -312,21 +311,19 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod uint64_t now = usecTimestampNow(); nodeData->setLastTimeBagEmpty(now); } - if (_encodedSomething) { - nodeData->stats.sceneCompleted(); - - ::endSceneSleepTime = _usleepTime; - unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; - - unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); - unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - if (_myServer->wantsDebugVoxelSending()) { - qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", - usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); - } - + // track completed scenes and send out the stats packet accordingly + nodeData->stats.sceneCompleted(); + ::endSceneSleepTime = _usleepTime; + unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + + unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); + unsigned long elapsedTime = nodeData->stats.getElapsedTime(); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + + if (true || _myServer->wantsDebugVoxelSending()) { + qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", + usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); } if (_myServer->wantDisplayVoxelStats()) { @@ -431,9 +428,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } } - if (bytesWritten > 0) { - _encodedSomething = true; - } nodeData->stats.encodeStopped(); _myServer->getServerTree().unlock(); } else { diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index f4ded44abd..ebd38ea146 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -43,8 +43,6 @@ private: unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; // used by environment sending code VoxelPacketData _packetData; - bool _encodedSomething; - }; #endif // __voxel_server__VoxelSendThread__ diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index fa5968a6e3..25d6380bb3 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -26,6 +26,8 @@ VoxelSceneStats::VoxelSceneStats() : reset(); _isReadyToSend = false; _isStarted = false; + _lastFullTotalEncodeTime = 0; + _lastFullElapsed = 0; } // copy constructor @@ -42,6 +44,9 @@ VoxelSceneStats& VoxelSceneStats::operator=(const VoxelSceneStats& other) { void VoxelSceneStats::copyFromOther(const VoxelSceneStats& other) { _totalEncodeTime = other._totalEncodeTime; + _elapsed = other._elapsed; + _lastFullTotalEncodeTime = other._lastFullTotalEncodeTime; + _lastFullElapsed = other._lastFullElapsed; _encodeStart = other._encodeStart; _packets = other._packets; @@ -174,6 +179,11 @@ void VoxelSceneStats::sceneCompleted() { _end = usecTimestampNow(); _elapsed = _end - _start; _elapsedAverage.updateAverage((float)_elapsed); + + if (_isFullScene) { + _lastFullElapsed = _elapsed; + _lastFullTotalEncodeTime = _totalEncodeTime; + } _statsMessageLength = packIntoMessage(_statsMessage, sizeof(_statsMessage)); _isReadyToSend = true; @@ -465,8 +475,15 @@ int VoxelSceneStats::unpackFromMessage(unsigned char* sourceBuffer, int availabl sourceBuffer += sizeof(_elapsed); memcpy(&_totalEncodeTime, sourceBuffer, sizeof(_totalEncodeTime)); sourceBuffer += sizeof(_totalEncodeTime); + memcpy(&_isFullScene, sourceBuffer, sizeof(_isFullScene)); sourceBuffer += sizeof(_isFullScene); + + if (_isFullScene) { + _lastFullElapsed = _elapsed; + _lastFullTotalEncodeTime = _totalEncodeTime; + } + memcpy(&_isMoving, sourceBuffer, sizeof(_isMoving)); sourceBuffer += sizeof(_isMoving); memcpy(&_packets, sourceBuffer, sizeof(_packets)); diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index c6f1eec966..e6ec63a6d0 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -148,6 +148,9 @@ public: unsigned long getTotalLeaves() const { return _totalLeaves; } unsigned long getTotalEncodeTime() const { return _totalEncodeTime; } unsigned long getElapsedTime() const { return _elapsed; } + + unsigned long getLastFullTotalEncodeTime() const { return _lastFullTotalEncodeTime; } + unsigned long getLastFullElapsedTime() const { return _lastFullElapsed; } private: @@ -162,11 +165,13 @@ private: uint64_t _start; uint64_t _end; uint64_t _elapsed; + uint64_t _lastFullElapsed; SimpleMovingAverage _elapsedAverage; SimpleMovingAverage _bitsPerVoxelAverage; uint64_t _totalEncodeTime; + uint64_t _lastFullTotalEncodeTime; uint64_t _encodeStart; // scene voxel related data From 21bf10b9bf0a0c4fcf2da73206d06f6f7e2d388d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 11:53:28 -0800 Subject: [PATCH 72/77] added expandable server details to voxel stats dialog --- interface/src/ui/VoxelStatsDialog.cpp | 46 ++++++++++++++++++--------- interface/src/ui/VoxelStatsDialog.h | 5 ++- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index 05cd3cf6b7..d8b4df62b0 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -27,6 +27,7 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model for (int i = 0; i < MAX_VOXEL_SERVERS; i++) { _voxelServerLables[i] = 0; + _extraServerDetails[i] = false; } for (int i = 0; i < MAX_STATS; i++) { @@ -45,6 +46,8 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model _localVoxelsMemory = AddStatItem("Voxels Memory"); _voxelsRendered = AddStatItem("Voxels Rendered"); _sendingMode = AddStatItem("Sending Mode"); + + layout()->setSizeConstraint(QLayout::SetFixedSize); } void VoxelStatsDialog::RemoveStatItem(int item) { @@ -57,9 +60,23 @@ void VoxelStatsDialog::RemoveStatItem(int item) { _labels[item] = NULL; } +void VoxelStatsDialog::moreless(const QString& link) { + QStringList linkDetails = link.split("-"); + const int COMMAND_ITEM = 0; + const int SERVER_NUMBER_ITEM = 1; + QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM]; + QString command = linkDetails[COMMAND_ITEM]; + int serverNumber = serverNumberString.toInt(); + if (command == "more") { + _extraServerDetails[serverNumber-1] = true; + } else { + _extraServerDetails[serverNumber-1] = false; + } +} + + int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { char strBuf[64]; - const int STATS_LABEL_WIDTH = 900; _statCount++; // increment our current stat count @@ -67,7 +84,6 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { static unsigned rotatingColors[] = { GREENISH, YELLOWISH, GREYISH }; colorRGBA = rotatingColors[_statCount % (sizeof(rotatingColors)/sizeof(rotatingColors[0]))]; } - QLabel* label = _labels[_statCount] = new QLabel(); // Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background) @@ -80,9 +96,6 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3); palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); label->setPalette(palette); - - label->setFixedWidth(STATS_LABEL_WIDTH); - snprintf(strBuf, sizeof(strBuf), " %s:", caption); _form->addRow(strBuf, label); @@ -218,7 +231,10 @@ void VoxelStatsDialog::showAllVoxelServers() { if (serverCount > _voxelServerLabelsCount) { char label[128] = { 0 }; sprintf(label, "Voxel Server %d",serverCount); - _voxelServerLables[serverCount-1] = AddStatItem(label); + int thisServerRow = _voxelServerLables[serverCount-1] = AddStatItem(label); + _labels[thisServerRow]->setTextFormat(Qt::RichText); + _labels[thisServerRow]->setTextInteractionFlags(Qt::TextBrowserInteraction); + connect(_labels[thisServerRow], SIGNAL(linkActivated(const QString&)), this, SLOT(moreless(const QString&))); _voxelServerLabelsCount++; } @@ -273,7 +289,7 @@ void VoxelStatsDialog::showAllVoxelServers() { QString internalString = locale.toString((uint)stats.getTotalInternal()); QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - serverDetails << "\n" << "Voxels: " << + serverDetails << "
" << "Voxels: " << totalString.toLocal8Bit().constData() << " total " << internalString.toLocal8Bit().constData() << " internal " << leavesString.toLocal8Bit().constData() << " leaves "; @@ -285,24 +301,24 @@ void VoxelStatsDialog::showAllVoxelServers() { QString lastFullEncodeString = locale.toString(lastFullEncode); QString lastFullSendString = locale.toString(lastFullSend); - serverDetails << "\n" << "Last Full Scene... " << + serverDetails << "
" << "Last Full Scene... " << "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; - - bool details = false; // for now, we'd like to add an expand/contract feature to each voxel server - if (details) { + + + if (_extraServerDetails[serverNumber-1]) { for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - serverDetails << "\n" << itemInfo.caption << " " << stats.getItemValue(item); + serverDetails << "
" << itemInfo.caption << " " << stats.getItemValue(item); } + serverDetails << " " << " [less...]"; + } else { + serverDetails << " " << " [more...]"; } } Application::getInstance()->unlockVoxelSceneStats(); - _labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); - - } // is VOXEL_SERVER } // Node Loop diff --git a/interface/src/ui/VoxelStatsDialog.h b/interface/src/ui/VoxelStatsDialog.h index 2099d5b122..7e00d4c37b 100644 --- a/interface/src/ui/VoxelStatsDialog.h +++ b/interface/src/ui/VoxelStatsDialog.h @@ -17,6 +17,7 @@ #define MAX_STATS 100 #define MAX_VOXEL_SERVERS 50 +#define DEFAULT_COLOR 0 class VoxelStatsDialog : public QDialog { Q_OBJECT @@ -30,6 +31,7 @@ signals: public slots: void reject(); + void moreless(const QString& link); protected: // State <- data model held by BandwidthMeter @@ -38,7 +40,7 @@ protected: // Emits a 'closed' signal when this dialog is closed. void closeEvent(QCloseEvent*); - int AddStatItem(const char* caption, unsigned colorRGBA = 0); + int AddStatItem(const char* caption, unsigned colorRGBA = DEFAULT_COLOR); void RemoveStatItem(int item); void showAllVoxelServers(); @@ -55,6 +57,7 @@ private: int _voxelsRendered; int _voxelServerLables[MAX_VOXEL_SERVERS]; int _voxelServerLabelsCount; + bool _extraServerDetails[MAX_VOXEL_SERVERS]; }; #endif /* defined(__interface__VoxelStatsDialog__) */ From 7f9d0849bd952155461eeada9e5a0fbeb5719bdf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 13:37:47 -0800 Subject: [PATCH 73/77] added more client side voxel stats including lost packets, out of order packets, and average flight time --- interface/src/Application.cpp | 18 ++++ interface/src/Application.h | 2 + interface/src/VoxelPacketProcessor.cpp | 6 ++ interface/src/ui/VoxelStatsDialog.cpp | 113 ++++++++++++++++------- interface/src/ui/VoxelStatsDialog.h | 5 +- libraries/voxels/src/VoxelSceneStats.cpp | 56 +++++++++++ libraries/voxels/src/VoxelSceneStats.h | 21 ++++- 7 files changed, 186 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3fc5cfb0a5..ec3beb7458 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4318,6 +4318,24 @@ void Application::nodeKilled(Node* node) { } } +void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, + sockaddr senderAddress, bool wasStatsPacket) { + + // Attempt to identify the sender from it's address. + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); + if (voxelServer) { + QUuid nodeUUID = voxelServer->getUUID(); + + // now that we know the node ID, let's add these stats to the stats for that node... + _voxelSceneStatsLock.lockForWrite(); + if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { + VoxelSceneStats& stats = _voxelServerSceneStats[nodeUUID]; + stats.trackIncomingVoxelPacket(messageData, messageLength, wasStatsPacket); + } + _voxelSceneStatsLock.unlock(); + } +} + int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server diff --git a/interface/src/Application.h b/interface/src/Application.h index 4695a1bf80..e2d0820ab9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -465,6 +465,8 @@ private: PieMenu _pieMenu; int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress); + void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, + sockaddr senderAddress, bool wasStatsPacket); NodeToJurisdictionMap _voxelServerJurisdictions; NodeToVoxelSceneStats _voxelServerSceneStats; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 5917e2fb05..011fb7f9ed 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -25,6 +25,8 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* ssize_t messageLength = packetLength; Application* app = Application::getInstance(); + bool wasStatsPacket = false; + // check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that if (app->_wantToKillLocalVoxels) { @@ -38,6 +40,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* if (packetData[0] == PACKET_TYPE_VOXEL_STATS) { int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderAddress); + wasStatsPacket = true; if (messageLength > statsMessageLength) { packetData += statsMessageLength; messageLength -= statsMessageLength; @@ -50,6 +53,9 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* } // fall through to piggyback message if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { + + app->trackIncomingVoxelPacket(packetData, messageLength, senderAddress, wasStatsPacket); + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index d8b4df62b0..9def2a2326 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -27,7 +27,7 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model for (int i = 0; i < MAX_VOXEL_SERVERS; i++) { _voxelServerLables[i] = 0; - _extraServerDetails[i] = false; + _extraServerDetails[i] = LESS; } for (int i = 0; i < MAX_STATS; i++) { @@ -67,16 +67,20 @@ void VoxelStatsDialog::moreless(const QString& link) { QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM]; QString command = linkDetails[COMMAND_ITEM]; int serverNumber = serverNumberString.toInt(); + if (command == "more") { - _extraServerDetails[serverNumber-1] = true; + _extraServerDetails[serverNumber-1] = MORE; + } else if (command == "most") { + _extraServerDetails[serverNumber-1] = MOST; } else { - _extraServerDetails[serverNumber-1] = false; + _extraServerDetails[serverNumber-1] = LESS; } } int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { char strBuf[64]; + const int STATS_LABEL_WIDTH = 600; _statCount++; // increment our current stat count @@ -98,6 +102,7 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { label->setPalette(palette); snprintf(strBuf, sizeof(strBuf), " %s:", caption); _form->addRow(strBuf, label); + label->setFixedWidth(STATS_LABEL_WIDTH); return _statCount; } @@ -213,7 +218,6 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) { showAllVoxelServers(); this->QDialog::paintEvent(event); - //this->setFixedSize(this->width(), this->height()); } void VoxelStatsDialog::showAllVoxelServers() { @@ -239,6 +243,8 @@ void VoxelStatsDialog::showAllVoxelServers() { } std::stringstream serverDetails(""); + std::stringstream extraDetails(""); + std::stringstream linkDetails(""); if (nodeList->getNodeActiveSocketOrPing(&(*node))) { serverDetails << "active "; @@ -247,7 +253,6 @@ void VoxelStatsDialog::showAllVoxelServers() { } QUuid nodeUUID = node->getUUID(); - serverDetails << " " << nodeUUID.toString().toLocal8Bit().constData() << " "; NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions(); @@ -280,44 +285,86 @@ void VoxelStatsDialog::showAllVoxelServers() { } // jurisdiction // now lookup stats details for this server... - Application::getInstance()->lockVoxelSceneStats(); - NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats(); - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - VoxelSceneStats& stats = sceneStats->at(nodeUUID); + if (_extraServerDetails[serverNumber-1] != LESS) { + Application::getInstance()->lockVoxelSceneStats(); + NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats(); + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + VoxelSceneStats& stats = sceneStats->at(nodeUUID); - QString totalString = locale.toString((uint)stats.getTotalVoxels()); - QString internalString = locale.toString((uint)stats.getTotalInternal()); - QString leavesString = locale.toString((uint)stats.getTotalLeaves()); + switch (_extraServerDetails[serverNumber-1]) { + case MOST: { + extraDetails << "
" ; + + const unsigned long USECS_PER_MSEC = 1000; + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - serverDetails << "
" << "Voxels: " << - totalString.toLocal8Bit().constData() << " total " << - internalString.toLocal8Bit().constData() << " internal " << - leavesString.toLocal8Bit().constData() << " leaves "; + QString lastFullEncodeString = locale.toString(lastFullEncode); + QString lastFullSendString = locale.toString(lastFullSend); + + extraDetails << "
" << "Last Full Scene... " << + "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << + "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; - const unsigned long USECS_PER_MSEC = 1000; - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { + VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); + VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + extraDetails << "
" << itemInfo.caption << " " << stats.getItemValue(item); + } + } // fall through... since MOST has all of MORE + case MORE: { + QString totalString = locale.toString((uint)stats.getTotalVoxels()); + QString internalString = locale.toString((uint)stats.getTotalInternal()); + QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - QString lastFullEncodeString = locale.toString(lastFullEncode); - QString lastFullSendString = locale.toString(lastFullSend); + serverDetails << "
" << "Node UUID: " << + nodeUUID.toString().toLocal8Bit().constData() << " "; - serverDetails << "
" << "Last Full Scene... " << - "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << - "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; + serverDetails << "
" << "Voxels: " << + totalString.toLocal8Bit().constData() << " total " << + internalString.toLocal8Bit().constData() << " internal " << + leavesString.toLocal8Bit().constData() << " leaves "; + + QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets()); + QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); + QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); + QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder()); + QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost()); + QString incomingFlightTimeString = locale.toString(stats.getIncomingFlightTimeAverage()); + + serverDetails << "
" << "Incoming Packets: " << + incomingPacketsString.toLocal8Bit().constData() << + " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() << + " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData(); + + serverDetails << "
" << + " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs"; + serverDetails << "
" << "Incoming" << + " Bytes: " << incomingBytesString.toLocal8Bit().constData() << + " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData(); + + serverDetails << extraDetails.str(); + if (_extraServerDetails[serverNumber-1] == MORE) { + linkDetails << " " << " [most...]"; + linkDetails << " " << " [less...]"; + } else { + linkDetails << " " << " [less...]"; + linkDetails << " " << " [least...]"; + } - if (_extraServerDetails[serverNumber-1]) { - for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { - VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); - VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - serverDetails << "
" << itemInfo.caption << " " << stats.getItemValue(item); + } break; + case LESS: { + // nothing + } break; } - serverDetails << " " << " [less...]"; - } else { - serverDetails << " " << " [more...]"; } + Application::getInstance()->unlockVoxelSceneStats(); + } else { + linkDetails << " " << " [more...]"; + linkDetails << " " << " [most...]"; } - Application::getInstance()->unlockVoxelSceneStats(); + serverDetails << linkDetails.str(); _labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); } // is VOXEL_SERVER } // Node Loop diff --git a/interface/src/ui/VoxelStatsDialog.h b/interface/src/ui/VoxelStatsDialog.h index 7e00d4c37b..eb95a87a7e 100644 --- a/interface/src/ui/VoxelStatsDialog.h +++ b/interface/src/ui/VoxelStatsDialog.h @@ -45,6 +45,9 @@ protected: void showAllVoxelServers(); private: + + typedef enum { LESS, MORE, MOST } details; + QFormLayout* _form; QLabel* _labels[MAX_STATS]; NodeToVoxelSceneStats* _model; @@ -57,7 +60,7 @@ private: int _voxelsRendered; int _voxelServerLables[MAX_VOXEL_SERVERS]; int _voxelServerLabelsCount; - bool _extraServerDetails[MAX_VOXEL_SERVERS]; + details _extraServerDetails[MAX_VOXEL_SERVERS]; }; #endif /* defined(__interface__VoxelStatsDialog__) */ diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index 25d6380bb3..ebda4448b6 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -13,6 +13,7 @@ #include #include +#include "VoxelPacketData.h" #include "VoxelNode.h" #include "VoxelSceneStats.h" @@ -21,6 +22,7 @@ const int samples = 100; VoxelSceneStats::VoxelSceneStats() : _elapsedAverage(samples), _bitsPerVoxelAverage(samples), + _incomingFlightTimeAverage(samples), _jurisdictionRoot(NULL) { reset(); @@ -28,6 +30,13 @@ VoxelSceneStats::VoxelSceneStats() : _isStarted = false; _lastFullTotalEncodeTime = 0; _lastFullElapsed = 0; + _incomingPacket = 0; + _incomingBytes = 0; + _incomingWastedBytes = 0; + _incomingLastSequence = 0; + _incomingOutOfOrder = 0; + _incomingLikelyLost = 0; + } // copy constructor @@ -121,6 +130,13 @@ void VoxelSceneStats::copyFromOther(const VoxelSceneStats& other) { _jurisdictionEndNodes.push_back(endNodeCodeCopy); } } + + _incomingPacket = other._incomingPacket; + _incomingBytes = other._incomingBytes; + _incomingWastedBytes = other._incomingWastedBytes; + _incomingLastSequence = other._incomingLastSequence; + _incomingOutOfOrder = other._incomingOutOfOrder; + _incomingLikelyLost = other._incomingLikelyLost; } @@ -782,4 +798,44 @@ const char* VoxelSceneStats::getItemValue(Item item) { return _itemValueBuffer; } +void VoxelSceneStats::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, bool wasStatsPacket) { + _incomingPacket++; + _incomingBytes += messageLength; + if (!wasStatsPacket) { + _incomingWastedBytes += (MAX_PACKET_SIZE - messageLength); + } + + int numBytesPacketHeader = numBytesForPacketHeader(messageData); + unsigned char* dataAt = messageData + numBytesPacketHeader; + + //VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); + dataAt += sizeof(VOXEL_PACKET_FLAGS); + VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + + VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SENT_TIME); + + //bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); + //bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); + + VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); + int flightTime = arrivedAt - sentAt; + const int USECS_PER_MSEC = 1000; + float flightTimeMsecs = flightTime / USECS_PER_MSEC; + _incomingFlightTimeAverage.updateAverage(flightTimeMsecs); + + + // detect out of order packets + if (sequence < _incomingLastSequence) { + _incomingOutOfOrder++; + } + + // detect likely lost packets + if (sequence > (_incomingLastSequence+1)) { + _incomingLikelyLost++; + } + + _incomingLastSequence = sequence; +} diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index e6ec63a6d0..526ccffadb 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -151,7 +151,17 @@ public: unsigned long getLastFullTotalEncodeTime() const { return _lastFullTotalEncodeTime; } unsigned long getLastFullElapsedTime() const { return _lastFullElapsed; } - + + // Used in client implementations to track individual voxel packets + void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, bool wasStatsPacket); + + unsigned int getIncomingPackets() const { return _incomingPacket; } + unsigned long getIncomingBytes() const { return _incomingBytes; } + unsigned long getIncomingWastedBytes() const { return _incomingWastedBytes; } + unsigned int getIncomingOutOfOrder() const { return _incomingOutOfOrder; } + unsigned int getIncomingLikelyLost() const { return _incomingLikelyLost; } + float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } + private: void copyFromOther(const VoxelSceneStats& other); @@ -236,6 +246,15 @@ private: unsigned long _bytes; unsigned int _passes; + // incoming packets stats + unsigned int _incomingPacket; + unsigned long _incomingBytes; + unsigned long _incomingWastedBytes; + unsigned int _incomingLastSequence; + unsigned int _incomingOutOfOrder; + unsigned int _incomingLikelyLost; + SimpleMovingAverage _incomingFlightTimeAverage; + // features related items bool _isMoving; bool _isFullScene; From 040ad1853e32582904c22d15672363b0ddf5ff33 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 15:33:48 -0800 Subject: [PATCH 74/77] properly handle sequence numbers to not skip when supressing duplicate packets --- interface/src/VoxelPacketProcessor.cpp | 1 + .../src/VoxelNodeData.cpp | 26 +++++++++-------- .../voxel-server-library/src/VoxelNodeData.h | 2 +- .../src/VoxelSendThread.cpp | 28 ++++++++++++------- libraries/voxels/src/VoxelSceneStats.cpp | 3 +- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 011fb7f9ed..b2374bc711 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -48,6 +48,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* return; // bail since piggyback data doesn't match our versioning } } else { + // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket() return; // bail since no piggyback data } } // fall through to piggyback message diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 6c18effa54..b7dec1053b 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -36,8 +36,7 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; _sequenceNumber = 0; - - resetVoxelPacket(); + resetVoxelPacket(true); // don't bump sequence } void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { @@ -48,8 +47,11 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { } bool VoxelNodeData::packetIsDuplicate() const { + // since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp + // of the entire packet, we need to compare only the packet content... if (_lastVoxelPacketLength == getPacketLength()) { - return memcmp(_lastVoxelPacket, _voxelPacket, getPacketLength()) == 0; + return memcmp(_lastVoxelPacket + VOXEL_PACKET_HEADER_SIZE, + _voxelPacket+VOXEL_PACKET_HEADER_SIZE , getPacketLength() - VOXEL_PACKET_HEADER_SIZE) == 0; } return false; } @@ -88,7 +90,7 @@ bool VoxelNodeData::shouldSuppressDuplicatePacket() { return shouldSuppress; } -void VoxelNodeData::resetVoxelPacket() { +void VoxelNodeData::resetVoxelPacket(bool lastWasSurpressed) { // Whenever we call this, we will keep a copy of the last packet, so we can determine if the last packet has // changed since we last reset it. Since we know that no two packets can ever be identical without being the same // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing @@ -124,7 +126,9 @@ void VoxelNodeData::resetVoxelPacket() { *sequenceAt = _sequenceNumber; _voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE); _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SEQUENCE); - _sequenceNumber++; + if (!(lastWasSurpressed || _lastVoxelPacketLength == VOXEL_PACKET_HEADER_SIZE)) { + _sequenceNumber++; + } // pack in timestamp VOXEL_PACKET_SENT_TIME now = usecTimestampNow(); @@ -144,12 +148,12 @@ void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { _voxelPacketAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); } - memcpy(_voxelPacketAt, buffer, bytes); - _voxelPacketAvailableBytes -= bytes; - _voxelPacketAt += bytes; - _voxelPacketWaiting = true; - - assert(_voxelPacketAvailableBytes >= 0); + if (bytes <= _voxelPacketAvailableBytes) { + memcpy(_voxelPacketAt, buffer, bytes); + _voxelPacketAvailableBytes -= bytes; + _voxelPacketAt += bytes; + _voxelPacketWaiting = true; + } } VoxelNodeData::~VoxelNodeData() { diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index fa0adc9e44..bd9e3eef16 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -27,7 +27,7 @@ public: VoxelNodeData(Node* owningNode); virtual ~VoxelNodeData(); - void resetVoxelPacket(); // resets voxel packet to after "V" header + void resetVoxelPacket(bool lastWasSurpressed = false); // resets voxel packet to after "V" header void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 8c84b924c1..679f4ff524 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -105,9 +105,17 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. if (nodeData->shouldSuppressDuplicatePacket()) { - nodeData->resetVoxelPacket(); // we still need to reset it though! + nodeData->resetVoxelPacket(true); // we still need to reset it though! return packetsSent; // without sending... } + + const unsigned char* messageData = nodeData->getPacket(); + int numBytesPacketHeader = numBytesForPacketHeader(messageData); + const unsigned char* dataAt = messageData + numBytesPacketHeader; + dataAt += sizeof(VOXEL_PACKET_FLAGS); + VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + // If we've got a stats message ready to send, then see if we can piggyback them together if (nodeData->stats.isReadyToSend()) { @@ -127,12 +135,12 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& int thisWastedBytes = 0; _totalWastedBytes += thisWastedBytes; _totalBytes += nodeData->getPacketLength(); - _totalPackets++; + _totalPackets++; if (debug) { - qDebug("Adding stats to packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Adding stats to packet at %llu [%llu]: sequence: %d size:%d [%llu] wasted bytes:%d [%llu]\n", now, _totalPackets, - nodeData->getPacketLength(), _totalBytes, + sequence, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); } @@ -147,13 +155,13 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // there was nothing else to send. int thisWastedBytes = 0; _totalWastedBytes += thisWastedBytes; - _totalBytes += nodeData->getPacketLength(); + _totalBytes += statsMessageLength; _totalPackets++; if (debug) { qDebug("Sending separate stats packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", now, _totalPackets, - nodeData->getPacketLength(), _totalBytes, + statsMessageLength, _totalBytes, thisWastedBytes, _totalWastedBytes); } @@ -171,10 +179,10 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Sending packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Sending packet at %llu [%llu]: sequence: %d size:%d [%llu] wasted bytes:%d [%llu]\n", now, _totalPackets, - nodeData->getPacketLength(), _totalBytes, + sequence, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); } } @@ -192,10 +200,10 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { - qDebug("Sending packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + qDebug("Sending packet at %llu [%llu]: sequence:%d size:%d [%llu] wasted bytes:%d [%llu]\n", now, _totalPackets, - nodeData->getPacketLength(), _totalBytes, + sequence, nodeData->getPacketLength(), _totalBytes, thisWastedBytes, _totalWastedBytes); } } diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index ebda4448b6..5bff303198 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -832,7 +832,8 @@ void VoxelSceneStats::trackIncomingVoxelPacket(unsigned char* messageData, ssize } // detect likely lost packets - if (sequence > (_incomingLastSequence+1)) { + VOXEL_PACKET_SEQUENCE expected = _incomingLastSequence+1; + if (sequence > expected) { _incomingLikelyLost++; } From f527ed6e7f80c4fb61e76cc24327069df3c7e846 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 15:35:00 -0800 Subject: [PATCH 75/77] removed debug --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 679f4ff524..b1a5b004b8 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -329,7 +329,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - if (true || _myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugVoxelSending()) { qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); } From ce90cd53820e2ff310d2b98fae26e2fa2a5ca666 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 15:48:53 -0800 Subject: [PATCH 76/77] removed accidentally added file --- .../shaders/point_size.vert.using-table | 257 ------------------ 1 file changed, 257 deletions(-) delete mode 100644 interface/resources/shaders/point_size.vert.using-table diff --git a/interface/resources/shaders/point_size.vert.using-table b/interface/resources/shaders/point_size.vert.using-table deleted file mode 100644 index c2113f926f..0000000000 --- a/interface/resources/shaders/point_size.vert.using-table +++ /dev/null @@ -1,257 +0,0 @@ -#version 120 - -attribute float voxelSizeIn; -varying float voxelSize; - -uniform float viewportWidth; -uniform float viewportHeight; -uniform vec3 cameraPosition; - -// Bit codes for faces -const int RIGHT = 1; -const int LEFT = 2; -const int BOTTOM = 4; -const int TOP = 8; -const int NEAR = 16; -const int FAR = 32; - -// index locations for the coordinates of the two vertices -const int X_ONE = 0; -const int Y_ONE = 1; -const int Z_ONE = 2; -const int X_TWO = 3; -const int Y_TWO = 4; -const int Z_TWO = 5; - -const int MAX_POSSIBLE_COMBINATIONS = 43; -const int COORD_PER_VERTEX = 3; -const int TWO_DISTANT_VERTICES = 2; -const int COORD_PER_LOOKUP = COORD_PER_VERTEX * TWO_DISTANT_VERTICES; -const int TOTAL_LOOKUP_COORDS = MAX_POSSIBLE_COMBINATIONS * COORD_PER_LOOKUP; -const int HALF_LOOKUP_COORDS = MAX_POSSIBLE_COMBINATIONS * COORD_PER_VERTEX; - - -// If we know the position of the camera relative to the voxel, we can apriori know the vertices that make the visible hull -// polygon. This also tells us which two vertices are known to make the longest possible distance between any pair of these -// vertices for the projected polygon. This is a lookup table based on this knowledge. - -// try switching these to indexes, and then using a switch statement... -const float coordLookup[TOTAL_LOOKUP_COORDS] = float[TOTAL_LOOKUP_COORDS] - ( - 0,0,0, 1,1,1, // 0 - inside - n/a - 0,0,0, 0,1,1, // 1 - right face, BOTTOM_RIGHT_NEAR to TOP_RIGHT_FAR - 1,0,0, 1,1,1, // 2 - left fact BOTTOM_LEFT_NEAR to TOP_LEFT_FAR - 0,0,0, 0,0,0, // n/a - 0,0,0, 1,0,1, // 4 - bottom face, BOTTOM_RIGHT_NEAR to BOTTOM_LEFT_FAR - 1,0,0, 0,1,1, // 5 - bottom, right - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 0,0,0, 1,1,1, // 6 - bottom, left - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 0,0,0, 0,0,0, // n/a - 0,1,0, 1,1,1, // 8 - top - TOP_RIGHT_NEAR to TOP_LEFT_FAR - 0,0,0, 1,1,1, // 9 - top, right - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 1,0,0, 0,1,1, //10 - top, left - BOTTOM_LEFT_NEAR to TOP_RIGHT_FAR - 0,0,0, 0,0,0, // n/a - 0,0,0, 0,0,0, // n/a - 0,0,0, 0,0,0, // n/a - 0,0,0, 0,0,0, // n/a - 0,0,0, 0,0,0, // n/a - 0,0,0, 1,1,1 , // 16 - front TODO - 0,0,0, 1,1,1 , // 17 front, right - TODO - 0,0,0, 1,1,1 , // 18 - front, left- TODO - 0,0,0, 0,0,0 , // n/a - 0,0,0, 1,1,1 , // 20 - front,bottom - TODO - 0,0,0, 1,1,1 , // 21 - front,bottom,right - TODO - 0,0,0, 1,1,1 , // 22 - front,bottom,left - TODO - 0,0,0, 0,0,0 , // n/a - 0,0,0, 1,1,1 , // 24 - front, top -TODO - 0,0,0, 1,1,1 , // 25 - front, top, right - TODO - 0,0,0, 1,1,1 , // 26 - front, top, left - TODO - 0,0,0, 0,0,0 , // n/a - 0,0,0, 0,0,0 , // n/a - 0,0,0, 0,0,0 , // n/a - 0,0,0, 0,0,0 , // n/a - 0,0,0, 0,0,0 , // n/a - 0,0,0, 1,1,1 , // 32 - far - TODO - 0,0,0, 1,1,1 , // 33 - back, right - TODO - 0,0,0, 1,1,1 , // 34 - back, left - TODO - 0,0,0, 0,0,0 , // n/a - 0,0,0, 1,1,1 , // 36 - back, bottom - TODO - 0,0,0, 1,1,1 , // 37 - back, bottom, right -TODO - 0,0,0, 1,1,1 , // 38 - back, bottom, left - TODO - 0,0,0, 0,0,0 , // n/a - 0,0,0, 1,1,1 , // 40 - back, top - TODO - 0,0,0, 1,1,1 , // 41 - back, top, right - TODO - 0,0,0, 1,1,1 // 42- back, top, left - TODO -); - -/** -const int COLORS_PER_LOOKUP = 3; -const int TOTAL_LOOKUP_COLORS = MAX_POSSIBLE_COMBINATIONS * COLORS_PER_LOOKUP; - -const float debugColorLookup[TOTAL_LOOKUP_COLORS] = float[TOTAL_LOOKUP_COLORS] - ( - 1,1,0, // n/a - 0,0,1, // 1 - right face, BOTTOM_RIGHT_NEAR to TOP_RIGHT_FAR - 0,0,1, // 2 - left fact BOTTOM_LEFT_NEAR to TOP_LEFT_FAR - 1,0,0, // n/a - 1,0,1, // 4 - bottom face, BOTTOM_RIGHT_NEAR to BOTTOM_LEFT_FAR - 1,0,1, // 5 - bottom, right - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 1,0,1, // 6 - bottom, left - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 1,0,0, // n/a - 0,1,1, // 8 - top - TOP_RIGHT_NEAR to TOP_LEFT_FAR - 0,1,1, // 9 - top, right - BOTTOM_RIGHT_NEAR to TOP_LEFT_FAR - 0,1,1, //10 - top, left - BOTTOM_LEFT_NEAR to TOP_RIGHT_FAR - 1,0,0, // n/a - 1,0,0, // n/a - 1,0,0, // n/a - 1,0,0, // n/a - 1,0,0, // n/a - 0,0,1, //16 - front or near - TODO - 0,0,1, // 17 - front, right - TODO - 0,0,1, // 18 - front, left - TODO - 1,0,0 , // n/a - 1,0,1, // 20 - front,bottom - TODO - 1,0,1, // 21 - front,bottom,right - TODO - 1,0,1, // 22 - front,bottom,left - TODO - 1,0,0 , // n/a - 0,1,1, // 24 - front, top - TODO - 0,1,1, // 25 - front, top, right - TODO - 0,1,1, // 26 - front, top, left - TODO - 1,0,0 , // n/a - 1,0,0 , // n/a - 1,0,0 , // n/a - 1,0,0 , // n/a - 1,0,0 , // n/a - 0,0,1, // 32 - back - TODO - 0,0,1, // 33 - back, right - TODO - 0,0,1, // 34 - back, left - TODO - 1,0,0, // n/a - 1,0,1, // 36 - back, bottom - TODO - 1,0,1, // 37 - back, bottom, right - TODO - 1,0,1, // 38 - back, bottom, left - TODO - 1,0,0 , // n/a - 0,1,1, // 40 - back, top - TODO - 0,1,1, // 41 - back, top, right - TODO - 0,1,1 // 42 - back, top, left - TODO -); - -**/ - -void main(void) { - vec4 debugColor = vec4(0,0,0,1); - - float voxelScreenWidth = 0; - float voxelScreenHeight = 0; - - - // Note: the gl_Vertex in this case are in "world coordinates" meaning they've already been scaled to TREE_SCALE - // this is also true for voxelSizeIn. - vec4 bottomNearRight = gl_Vertex; - vec4 topFarLeft = (gl_Vertex + vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0)); - - int lookUp = 0; - int lookUpBase = 0; - - // In order to use our lookup table above, we need to encode the 6-bit code to classify camera relative to the 6 defining - // planes of the voxel. Based on camera position relative to the bottomNearRight corner and the topFarLeft corner, we can - // calculate which hull and therefore which two vertices are furthest apart liniarly once projected - if (cameraPosition.x < bottomNearRight.x) { - lookUp += RIGHT; - } - if (cameraPosition.x > topFarLeft.x) { - lookUp += LEFT; - } - if (cameraPosition.y < bottomNearRight.y) { - lookUp += BOTTOM; - } - if (cameraPosition.y > topFarLeft.y) { - lookUp += TOP; - } - if (cameraPosition.z < bottomNearRight.z) { - lookUp += NEAR; - } - if (cameraPosition.z > topFarLeft.z) { - lookUp += FAR; - } - - //if (cameraPositionZ > gl_Vertex.z) { - // debugColor = vec4(0,1,0,1); - //} - - const bool useLookup = false; - if (true) { - lookUpBase = lookUp * COORD_PER_LOOKUP; - vec4 cornerAdjustOne = vec4(coordLookup[lookUpBase + 0], - coordLookup[lookUpBase + 1], - coordLookup[lookUpBase + 2], 0) * voxelSizeIn; - - - float xTwo = coordLookup[lookUpBase + 3]; - float yTwo = coordLookup[lookUpBase + 4]; - float zTwo = coordLookup[lookUpBase + 5]; - - vec4 cornerAdjustTwo = vec4(xTwo, yTwo, zTwo, 0) * voxelSizeIn; - - /** - vec4 cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; - vec4 cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; - **/ - - vec4 cornerOne = gl_Vertex + cornerAdjustOne; - vec4 cornerTwo = gl_Vertex + cornerAdjustTwo; - - vec4 cornerOneMVP = gl_ModelViewProjectionMatrix * cornerOne; - vec4 cornerTwoMVP = gl_ModelViewProjectionMatrix * cornerTwo; - - vec2 cornerOneScreen = vec2(cornerOneMVP.x / cornerOneMVP.w, cornerOneMVP.y / cornerOneMVP.w); - if (cornerOneMVP.w < 0) { - cornerOneScreen.x = -cornerOneScreen.x; - cornerOneScreen.y = -cornerOneScreen.y; - } - - vec2 cornerTwoScreen = vec2(cornerTwoMVP.x / cornerTwoMVP.w, cornerTwoMVP.y / cornerTwoMVP.w); - if (cornerTwoMVP.w < 0) { - cornerTwoScreen.x = -cornerTwoScreen.x; - cornerTwoScreen.y = -cornerTwoScreen.y; - } - voxelScreenWidth = abs(cornerOneScreen.x - cornerTwoScreen.x) * viewportWidth / 2.0; - voxelScreenHeight = abs(cornerOneScreen.y - cornerTwoScreen.y) * viewportHeight / 2.0; - } //else - - if (false) { - vec4 corner = gl_ModelViewProjectionMatrix * gl_Vertex; - vec4 farCornerVertex = gl_Vertex; - farCornerVertex += vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0); - vec4 farCorner = gl_ModelViewProjectionMatrix * farCornerVertex; - - // math! If the w result is negative then the point is behind the viewer - vec2 cornerOnScreen = vec2(corner.x / corner.w, corner.y / corner.w); - if (corner.w < 0) { - cornerOnScreen.x = -cornerOnScreen.x; - cornerOnScreen.y = -cornerOnScreen.y; - } - - vec2 farCornerOnScreen = vec2(farCorner.x / farCorner.w, farCorner.y / farCorner.w); - if (farCorner.w < 0) { - farCornerOnScreen.x = -farCornerOnScreen.x; - farCornerOnScreen.y = -farCornerOnScreen.y; - } - - voxelScreenWidth = abs(farCornerOnScreen.x - cornerOnScreen.x) * viewportWidth / 2.0; - voxelScreenHeight = abs(farCornerOnScreen.y - cornerOnScreen.y) * viewportHeight / 2.0; - } - - float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); - - vec4 centerVertex = gl_Vertex; - float halfSizeIn = voxelSizeIn / 2; - centerVertex += vec4(halfSizeIn, halfSizeIn, halfSizeIn, 0.0); - vec4 center = gl_ModelViewProjectionMatrix * centerVertex; - - gl_Position = center; - gl_PointSize = voxelScreenLength; - - //int debugColorBase = lookUp * COLORS_PER_LOOKUP; - //debugColor = vec4(debugColorLookup[debugColorBase], debugColorLookup[debugColorBase + 1], debugColorLookup[debugColorBase + 2], 1); - - gl_FrontColor = debugColor; // gl_Color; // set the color.. -} \ No newline at end of file From a3b69c1e758fbfc5fdd3f756fc209797adad94d3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 27 Nov 2013 15:55:49 -0800 Subject: [PATCH 77/77] bumb version number of PACKET_TYPE_VOXEL_QUERY --- libraries/shared/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 1bd71e35eb..5d5f812760 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -37,7 +37,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 1; case PACKET_TYPE_VOXEL_QUERY: - return 1; + return 2; case PACKET_TYPE_SET_VOXEL: case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: