pack more compressed sections into wire packets if there is room

This commit is contained in:
ZappoMan 2013-11-26 22:18:24 -08:00
parent b7ee2ea2db
commit dac211cebd
6 changed files with 133 additions and 43 deletions

View file

@ -619,26 +619,41 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE;
if (packetIsCompressed && dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { int subsection = 1;
sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); while (dataBytes > 0) {
dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); if (packetIsCompressed) {
} else { if (dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) {
sectionLength = dataBytes; 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; subsection++;
// 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();
} }
break; break;
} }

View file

@ -16,7 +16,7 @@
VoxelNodeData::VoxelNodeData(Node* owningNode) : VoxelNodeData::VoxelNodeData(Node* owningNode) :
VoxelQuery(owningNode), VoxelQuery(owningNode),
_viewSent(false), _viewSent(false),
_voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), _voxelPacketAvailableBytes(MAX_PACKET_SIZE),
_maxSearchLevel(1), _maxSearchLevel(1),
_maxLevelReachedInLastSearch(1), _maxLevelReachedInLastSearch(1),
_lastTimeBagEmpty(0), _lastTimeBagEmpty(0),
@ -30,9 +30,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_lodChanged(false), _lodChanged(false),
_lodInitialized(false) _lodInitialized(false)
{ {
_voxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _voxelPacket = new unsigned char[MAX_PACKET_SIZE];
_voxelPacketAt = _voxelPacket; _voxelPacketAt = _voxelPacket;
_lastVoxelPacket = new unsigned char[_voxelPacketAvailableBytes]; _lastVoxelPacket = new unsigned char[MAX_PACKET_SIZE];
_lastVoxelPacketLength = 0; _lastVoxelPacketLength = 0;
_duplicatePacketCount = 0; _duplicatePacketCount = 0;
_sequenceNumber = 0; _sequenceNumber = 0;
@ -108,18 +108,22 @@ void VoxelNodeData::resetVoxelPacket() {
setAtBit(flags,PACKET_IS_COMPRESSED_BIT); setAtBit(flags,PACKET_IS_COMPRESSED_BIT);
} }
_voxelPacketAvailableBytes = MAX_PACKET_SIZE;
int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA); int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA);
_voxelPacketAt = _voxelPacket + numBytesPacketHeader; _voxelPacketAt = _voxelPacket + numBytesPacketHeader;
_voxelPacketAvailableBytes -= numBytesPacketHeader;
// pack in flags // pack in flags
VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt; VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt;
*flagsAt = flags; *flagsAt = flags;
_voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS); _voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS);
_voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_FLAGS);
// pack in sequence number // pack in sequence number
VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt; VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt;
*sequenceAt = _sequenceNumber; *sequenceAt = _sequenceNumber;
_voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE); _voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE);
_voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SEQUENCE);
_sequenceNumber++; _sequenceNumber++;
// pack in timestamp // pack in timestamp
@ -127,8 +131,8 @@ void VoxelNodeData::resetVoxelPacket() {
VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt; VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt;
*timeAt = now; *timeAt = now;
_voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME); _voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME);
_voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SENT_TIME);
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_DATA_SIZE;
_voxelPacketWaiting = false; _voxelPacketWaiting = false;
} }
@ -144,6 +148,8 @@ void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) {
_voxelPacketAvailableBytes -= bytes; _voxelPacketAvailableBytes -= bytes;
_voxelPacketAt += bytes; _voxelPacketAt += bytes;
_voxelPacketWaiting = true; _voxelPacketWaiting = true;
assert(_voxelPacketAvailableBytes >= 0);
} }
VoxelNodeData::~VoxelNodeData() { VoxelNodeData::~VoxelNodeData() {

View file

@ -32,7 +32,7 @@ public:
void writeToPacket(const 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; } 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 isPacketWaiting() const { return _voxelPacketWaiting; }
bool packetIsDuplicate() const; bool packetIsDuplicate() const;

View file

@ -251,9 +251,14 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
} }
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
} }
int uncompressedSize = !wantCompression ? MAX_VOXEL_PACKET_DATA_SIZE int targetSize = MAX_VOXEL_PACKET_DATA_SIZE;
: MAX_VOXEL_PACKET_DATA_SIZE - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); if (wantCompression) {
_packetData.changeSettings(wantCompression, uncompressedSize); 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()) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
@ -315,7 +320,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
unsigned long elapsedTime = nodeData->stats.getElapsedTime(); unsigned long elapsedTime = nodeData->stats.getElapsedTime();
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); 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", 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); usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes);
} }
@ -373,6 +378,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval);
} }
int extraPackingAttempts = 0;
while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", 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(); nodeData->stats.encodeStarted();
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params);
if (_packetData.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { // if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case.
lastNodeDidntFit = true; 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) { 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... 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 // 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 // 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. // mean we should send the previous packet contents and reset it.
bool sendNow = lastNodeDidntFit; if (lastNodeDidntFit) {
if (_packetData.hasContent() && sendNow) { if (_packetData.hasContent()) {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { // if for some reason the finalized size is greater than our available size, then probably the "compressed"
printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", // form actually inflated beyond our padding, and in this case we will send the current packet, then
_packetData.getFinalizedSize(), _packetData.getUncompressedSize()); // 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); // If we're not running compressed, the we know we can just send now. Or if we're running compressed, but
_packetData.reset(); // 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
} }
} }

View file

@ -28,11 +28,7 @@ void VoxelPacketData::changeSettings(bool enableCompression, int targetSize) {
void VoxelPacketData::reset() { void VoxelPacketData::reset() {
_bytesInUse = 0; _bytesInUse = 0;
if (_enableCompression) { _bytesAvailable = _targetSize;
_bytesAvailable = MAX_VOXEL_UNCOMRESSED_PACKET_SIZE;
} else {
_bytesAvailable = _targetSize;
}
_subTreeAt = 0; _subTreeAt = 0;
_compressedBytes = 0; _compressedBytes = 0;
_bytesInUseLastCheck = 0; _bytesInUseLastCheck = 0;

View file

@ -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 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_COLOR_BIT = 0;
const int PACKET_IS_COMPRESSED_BIT = 1; const int PACKET_IS_COMPRESSED_BIT = 1;
@ -121,6 +125,7 @@ public:
void loadFinalizedContent(const unsigned char* data, int length); void loadFinalizedContent(const unsigned char* data, int length);
bool isCompressed() const { return _enableCompression; } bool isCompressed() const { return _enableCompression; }
int getTargetSize() const { return _targetSize; }
void debugContent(); void debugContent();