diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 289b1161e6..98990011da 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -16,7 +16,8 @@ VoxelAgentData::VoxelAgentData(Agent* owningAgent) : _viewSent(false), _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), _maxSearchLevel(1), - _maxLevelReachedInLastSearch(1) + _maxLevelReachedInLastSearch(1), + _lastTimeBagEmpty(0) { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 6606530b94..f7e04329a0 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -50,6 +50,10 @@ public: bool getViewSent() const { return _viewSent; }; void setViewSent(bool viewSent) { _viewSent = viewSent; } + long long getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; + void setLastTimeBagEmpty(long long lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; + + private: VoxelAgentData(const VoxelAgentData &); VoxelAgentData& operator= (const VoxelAgentData&); @@ -63,6 +67,7 @@ private: int _maxLevelReachedInLastSearch; ViewFrustum _currentViewFrustum; ViewFrustum _lastKnownViewFrustum; + long long _lastTimeBagEmpty; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index a73a8dd09a..af7f321d5e 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -46,6 +46,7 @@ const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; int PACKETS_PER_CLIENT_PER_INTERVAL = 30; +const int SENDING_TIME_TO_SPARE = 20 * 1000; // usec of sending interval to spare for calculating voxels const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -263,6 +264,29 @@ void deepestLevelVoxelDistributor(AgentList* agentList, // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || agentData->nodeBag.isEmpty()) { + if (::debugVoxelSending) { + printf("(viewFrustumChanged=%s || agentData->nodeBag.isEmpty() =%s)...\n", + debug::valueOf(viewFrustumChanged), debug::valueOf(agentData->nodeBag.isEmpty())); + long long now = usecTimestampNow(); + if (agentData->getLastTimeBagEmpty() > 0) { + float elapsedSceneSend = (now - agentData->getLastTimeBagEmpty()) / 1000000.0f; + + if (viewFrustumChanged) { + printf("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend); + } else { + printf("elapsed time to send scene = %f seconds", elapsedSceneSend); + } + printf(" [occlusionCulling: %s]\n", debug::valueOf(agentData->getWantOcclusionCulling())); + } + agentData->setLastTimeBagEmpty(now); + } + + // if our view has changed, we need to reset these things... + if (viewFrustumChanged) { + agentData->nodeBag.deleteAll(); + agentData->map.erase(); + } + // For now, we're going to disable the "search for colored nodes" because that strategy doesn't work when we support // deletion of nodes. Instead if we just start at the root we get the correct behavior we want. We are keeping this @@ -310,6 +334,22 @@ void deepestLevelVoxelDistributor(AgentList* agentList, bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { + + // Check to see if we're taking too long, and if so bail early... + long long 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 (::debugVoxelSending) { + 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, + agentData->nodeBag.count()); + } + break; + } + if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); @@ -322,7 +362,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag, params); - + if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { @@ -379,7 +419,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, if (agentData->nodeBag.isEmpty()) { agentData->updateLastKnownViewFrustum(); agentData->setViewSent(true); - agentData->map.erase(); + agentData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes }