fix issue where we sometimes don't completely fill a packet mid scene

This commit is contained in:
ZappoMan 2013-11-24 20:29:54 -08:00
parent 0cd269632e
commit ed80895eb3
4 changed files with 61 additions and 9 deletions

View file

@ -350,6 +350,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
break; break;
} }
bool lastNodeDidntFit = false; // assume each node fits
if (!nodeData->nodeBag.isEmpty()) { if (!nodeData->nodeBag.isEmpty()) {
VoxelNode* subTree = nodeData->nodeBag.extract(); VoxelNode* subTree = nodeData->nodeBag.extract();
bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
@ -375,11 +376,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
_myServer->getServerTree().lockForRead(); _myServer->getServerTree().lockForRead();
nodeData->stats.encodeStarted(); nodeData->stats.encodeStarted();
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_tempPacket, nodeData->nodeBag, params);
if (_tempPacket.hasContent() && bytesWritten == 0 && _tempPacket.getFinalizedSize() < 1450) { if (_tempPacket.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
printf(">>>>>>>>>>>>>>> got bytesWritten==0 _tempPacket.getFinalizedSize()=%d <<<<<<<<<<<<<<<\n", lastNodeDidntFit = true;
_tempPacket.getFinalizedSize());
} }
if (bytesWritten > 0) { 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 // 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 // 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 = (bytesWritten == 0); bool sendNow = lastNodeDidntFit;
if (_tempPacket.hasContent() && sendNow) { if (_tempPacket.hasContent() && sendNow) {
if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) {
printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n", printf("calling writeToPacket() compressedSize=%d uncompressedSize=%d\n",

View file

@ -11,7 +11,12 @@
// * determine why we sometimes don't fill packets very well (rarely) mid-scene... sometimes it appears as if // * 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 // 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 // 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 // * 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 // * improve semantics for "reshuffle" - current approach will work for now and with compression

View file

@ -1031,6 +1031,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
// you can't call this without a valid node // you can't call this without a valid node
if (!node) { if (!node) {
qDebug("WARNING! encodeTreeBitstream() called with node=NULL\n"); qDebug("WARNING! encodeTreeBitstream() called with node=NULL\n");
params.stopReason = EncodeBitstreamParams::NULL_NODE;
return bytesWritten; 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 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)) { if (params.viewFrustum && !node->isInView(*params.viewFrustum)) {
doneEncoding(node); doneEncoding(node);
params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW;
return bytesWritten; return bytesWritten;
} }
@ -1063,6 +1065,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
if (!roomForOctalCode) { if (!roomForOctalCode) {
doneEncoding(node); doneEncoding(node);
bag.insert(node); // add the node back to the bag so it will eventually get included bag.insert(node); // add the node back to the bag so it will eventually get included
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
return bytesWritten; 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 // couldn't be written... so reset them here... This isn't true for the non-color included case
if (params.includeColor && childBytesWritten == 2) { if (params.includeColor && childBytesWritten == 2) {
childBytesWritten = 0; childBytesWritten = 0;
//params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT...
} }
// if we wrote child bytes, then return our result of all bytes written // if we wrote child bytes, then return our result of all bytes written
@ -1093,6 +1097,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node,
} else { } else {
// otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code
bytesWritten = 0; bytesWritten = 0;
//params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
} }
if (bytesWritten == 0) { if (bytesWritten == 0) {
@ -1115,6 +1120,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// you can't call this without a valid node // you can't call this without a valid node
if (!node) { if (!node) {
qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL\n"); qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL\n");
params.stopReason = EncodeBitstreamParams::NULL_NODE;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1125,6 +1131,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
// If we've reached our max Search Level, then stop searching. // If we've reached our max Search Level, then stop searching.
if (currentEncodeLevel >= params.maxEncodeLevel) { if (currentEncodeLevel >= params.maxEncodeLevel) {
params.stopReason = EncodeBitstreamParams::TOO_DEEP;
return bytesAtThisLevel; 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. // 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. // 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)) { if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), CHECK_NODE_ONLY)) {
params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
} }
@ -1148,6 +1156,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
if (params.stats) { if (params.stats) {
params.stats->skippedDistance(node); params.stats->skippedDistance(node);
} }
params.stopReason = EncodeBitstreamParams::LOD_SKIP;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1158,6 +1167,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
if (params.stats) { if (params.stats) {
params.stats->skippedOutOfView(node); params.stats->skippedOutOfView(node);
} }
params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1197,6 +1207,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
if (params.stats) { if (params.stats) {
params.stats->skippedWasInView(node); params.stats->skippedWasInView(node);
} }
params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1207,6 +1218,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
if (params.stats) { if (params.stats) {
params.stats->skippedNoChange(node); params.stats->skippedNoChange(node);
} }
params.stopReason = EncodeBitstreamParams::NO_CHANGE;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
@ -1226,6 +1238,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
if (params.stats) { if (params.stats) {
params.stats->skippedOccluded(node); params.stats->skippedOccluded(node);
} }
params.stopReason = EncodeBitstreamParams::OCCLUDED;
return bytesAtThisLevel; return bytesAtThisLevel;
} }
} else { } else {
@ -1616,7 +1629,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node,
params.stats->didntFit(node); params.stats->didntFit(node);
} }
return 0; params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
bytesAtThisLevel = 0; // didn't fit
} }
return bytesAtThisLevel; return bytesAtThisLevel;

View file

@ -66,6 +66,21 @@ public:
CoverageMap* map; CoverageMap* map;
JurisdictionMap* jurisdictionMap; 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( EncodeBitstreamParams(
int maxEncodeLevel = INT_MAX, int maxEncodeLevel = INT_MAX,
const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM,
@ -97,8 +112,27 @@ public:
forceSendScene(forceSendScene), forceSendScene(forceSendScene),
stats(stats), stats(stats),
map(map), 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 { class ReadBitstreamToTreeParams {