mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge pull request #1111 from ZappoMan/rate_control
added suppression of duplicate voxel packets to save on bit/packet rate
This commit is contained in:
commit
ba5db325aa
3 changed files with 66 additions and 2 deletions
|
@ -27,6 +27,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
|
|||
{
|
||||
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||
_voxelPacketAt = _voxelPacket;
|
||||
_lastVoxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||
_lastVoxelPacketLength = 0;
|
||||
_duplicatePacketCount = 0;
|
||||
resetVoxelPacket();
|
||||
}
|
||||
|
||||
|
@ -37,9 +40,55 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
|||
_voxelSendThread->initialize(true);
|
||||
}
|
||||
|
||||
bool VoxelNodeData::packetIsDuplicate() const {
|
||||
if (_lastVoxelPacketLength == getPacketLength()) {
|
||||
return memcmp(_lastVoxelPacket, _voxelPacket, getPacketLength()) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VoxelNodeData::shouldSuppressDuplicatePacket() {
|
||||
bool shouldSuppress = false; // assume we won't suppress
|
||||
|
||||
// only consider duplicate packets
|
||||
if (packetIsDuplicate()) {
|
||||
_duplicatePacketCount++;
|
||||
|
||||
// If this is the first suppressed packet, remember our time...
|
||||
if (_duplicatePacketCount == 1) {
|
||||
_firstSuppressedPacket = usecTimestampNow();
|
||||
}
|
||||
|
||||
// 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;
|
||||
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) {
|
||||
shouldSuppress = true;
|
||||
}
|
||||
} else {
|
||||
// Reset our count, we've reached our maximum time.
|
||||
_duplicatePacketCount = 0;
|
||||
}
|
||||
} else {
|
||||
// Reset our count, it wasn't a duplicate
|
||||
_duplicatePacketCount = 0;
|
||||
}
|
||||
return shouldSuppress;
|
||||
}
|
||||
|
||||
void VoxelNodeData::resetVoxelPacket() {
|
||||
// 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
|
||||
// packet send rate.
|
||||
_lastVoxelPacketLength = getPacketLength();
|
||||
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.
|
||||
_currentPacketIsColor = (LOW_RES_MONO && getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor();
|
||||
|
|
|
@ -33,6 +33,10 @@ public:
|
|||
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 shouldSuppressDuplicatePacket();
|
||||
|
||||
int getAvailable() const { return _voxelPacketAvailableBytes; }
|
||||
int getMaxSearchLevel() const { return _maxSearchLevel; };
|
||||
void resetMaxSearchLevel() { _maxSearchLevel = 1; };
|
||||
|
@ -78,6 +82,12 @@ private:
|
|||
unsigned char* _voxelPacketAt;
|
||||
int _voxelPacketAvailableBytes;
|
||||
bool _voxelPacketWaiting;
|
||||
|
||||
unsigned char* _lastVoxelPacket;
|
||||
int _lastVoxelPacketLength;
|
||||
int _duplicatePacketCount;
|
||||
uint64_t _firstSuppressedPacket;
|
||||
|
||||
int _maxSearchLevel;
|
||||
int _maxLevelReachedInLastSearch;
|
||||
ViewFrustum _currentViewFrustum;
|
||||
|
|
|
@ -59,6 +59,13 @@ bool VoxelSendThread::process() {
|
|||
|
||||
void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) {
|
||||
|
||||
// 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
|
||||
// this rate control savings.
|
||||
if (nodeData->shouldSuppressDuplicatePacket()) {
|
||||
return; // without sending...
|
||||
}
|
||||
|
||||
// If we've got a stats message ready to send, then see if we can piggyback them together
|
||||
if (nodeData->stats.isReadyToSend()) {
|
||||
// Send the stats message to the client
|
||||
|
@ -254,13 +261,11 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
|||
} else {
|
||||
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||
packetsSentThisInterval++;
|
||||
nodeData->resetVoxelPacket();
|
||||
nodeData->writeToPacket(_tempOutputBuffer, bytesWritten);
|
||||
}
|
||||
} else {
|
||||
if (nodeData->isPacketWaiting()) {
|
||||
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||
nodeData->resetVoxelPacket();
|
||||
}
|
||||
packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue