From ed80895eb3d6b992c9873e8be72df38bdefc2b7d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 24 Nov 2013 20:29:54 -0800 Subject: [PATCH] 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 {