more voxel scene stats

This commit is contained in:
ZappoMan 2013-07-18 14:13:45 -07:00
parent 65f550e68e
commit 3aa6af21b1
5 changed files with 312 additions and 77 deletions

View file

@ -8,70 +8,179 @@
#include <SharedUtil.h>
#include "VoxelNode.h"
#include "VoxelSceneStats.h"
VoxelSceneStats::VoxelSceneStats() :
start(0),
end(0),
elapsed(0),
total(0),
traversed(0),
internal(0),
internalOutOfView(0),
internalOccluded(0),
internalDirty(0),
leaves(0),
leavesOutOfView(0),
leavesOccluded(0),
leavesDirty(0),
packets(0),
bytes(0),
passes(0),
wasFinished(false),
wasMoving(false),
hadDeltaView(false),
hadOcclusionCulling(false)
{
VoxelSceneStats::VoxelSceneStats() {
reset();
}
VoxelSceneStats::~VoxelSceneStats() {
}
void VoxelSceneStats::sceneStarted() {
start = usecTimestampNow();
void VoxelSceneStats::sceneStarted(bool fullScene, bool moving) {
_start = usecTimestampNow();
reset(); // resets packet and voxel stats
_fullSceneDraw = fullScene;
_moving = moving;
}
void VoxelSceneStats::sceneCompleted() {
end = usecTimestampNow();
elapsed = end - start;
_end = usecTimestampNow();
_elapsed = _end - _start;
}
void VoxelSceneStats::reset() {
start = 0;
end= 0;
elapsed= 0;
_packets = 0;
_bytes = 0;
_passes = 0;
_traversed = 0;
_internal = 0;
_leaves = 0;
_skippedDistance = 0;
_internalSkippedDistance = 0;
_leavesSkippedDistance = 0;
_skippedOutOfView = 0;
_internalSkippedOutOfView = 0;
_leavesSkippedOutOfView = 0;
_skippedWasInView = 0;
_internalSkippedWasInView = 0;
_leavesSkippedWasInView = 0;
_skippedNoChange = 0;
_internalSkippedNoChange = 0;
_leavesSkippedNoChange = 0;
_skippedOccluded = 0;
_internalSkippedOccluded = 0;
_leavesSkippedOccluded = 0;
_colorSent = 0;
_internalColorSent = 0;
_leavesColorSent = 0;
_didntFit = 0;
_internalDidntFit = 0;
_leavesDidntFit = 0;
total = 0;
traversed = 0;
internal = 0;
internalOutOfView = 0;
internalOccluded = 0;
internalDirty = 0;
leaves = 0;
leavesOutOfView = 0;
leavesOccluded = 0;
leavesDirty = 0;
packets = 0;
bytes = 0;
passes = 0;
wasFinished = false;
wasMoving = false;
hadDeltaView = false;
hadOcclusionCulling = false;
}
void VoxelSceneStats::packetSent(int bytes) {
_packets++;
_bytes += bytes;
}
void VoxelSceneStats::traversed(const VoxelNode* node) {
_traversed++;
if (node->isLeaf()) {
_leaves++;
} else {
_internal++;
}
}
void VoxelSceneStats::skippedDistance(const VoxelNode* node) {
_skippedDistance++;
if (node->isLeaf()) {
_leavesSkippedDistance++;
} else {
_internalSkippedDistance++;
}
}
void VoxelSceneStats::skippedOutOfView(const VoxelNode* node) {
_skippedOutOfView++;
if (node->isLeaf()) {
_leavesSkippedOutOfView++;
} else {
_internalSkippedOutOfView++;
}
}
void VoxelSceneStats::skippedWasInView(const VoxelNode* node) {
_skippedWasInView++;
if (node->isLeaf()) {
_leavesSkippedWasInView++;
} else {
_internalSkippedWasInView++;
}
}
void VoxelSceneStats::skippedNoChange(const VoxelNode* node) {
_skippedNoChange++;
if (node->isLeaf()) {
_leavesSkippedNoChange++;
} else {
_internalSkippedNoChange++;
}
}
void VoxelSceneStats::skippedOccluded(const VoxelNode* node) {
_skippedOccluded++;
if (node->isLeaf()) {
_leavesSkippedOccluded++;
} else {
_internalSkippedOccluded++;
}
}
void VoxelSceneStats::colorSent(const VoxelNode* node) {
_colorSent++;
if (node->isLeaf()) {
_leavesColorSent++;
} else {
_internalColorSent++;
}
}
void VoxelSceneStats::didntFit(const VoxelNode* node) {
_didntFit++;
if (node->isLeaf()) {
_leavesDidntFit++;
} else {
_internalDidntFit++;
}
}
void VoxelSceneStats::printDebugDetails() {
qDebug("VoxelSceneStats: start: %llu, end: %llu, elapsed: %llu \n", start, end, elapsed);
qDebug("\n------------------------------\n");
qDebug("VoxelSceneStats:\n");
qDebug(" start : %llu \n", _start);
qDebug(" end : %llu \n", _end);
qDebug(" elapsed: %llu \n", _elapsed);
qDebug("\n");
qDebug(" full scene: %s\n", debug::valueOf(_fullSceneDraw));
qDebug(" moving: %s\n", debug::valueOf(_moving));
qDebug("\n");
qDebug(" packets: %d\n", _packets);
qDebug(" bytes : %d\n", _bytes);
qDebug("\n");
qDebug(" traversed : %lu\n", _traversed );
qDebug(" internal : %lu\n", _internal );
qDebug(" leaves : %lu\n", _leaves );
qDebug(" skipped distance : %lu\n", _skippedDistance );
qDebug(" internal : %lu\n", _internalSkippedDistance );
qDebug(" leaves : %lu\n", _leavesSkippedDistance );
qDebug(" skipped out of view : %lu\n", _skippedOutOfView );
qDebug(" internal : %lu\n", _internalSkippedOutOfView );
qDebug(" leaves : %lu\n", _leavesSkippedOutOfView );
qDebug(" skipped was in view : %lu\n", _skippedWasInView );
qDebug(" internal : %lu\n", _internalSkippedWasInView );
qDebug(" leaves : %lu\n", _leavesSkippedWasInView );
qDebug(" skipped no change : %lu\n", _skippedNoChange );
qDebug(" internal : %lu\n", _internalSkippedNoChange );
qDebug(" leaves : %lu\n", _leavesSkippedNoChange );
qDebug(" skipped occluded : %lu\n", _skippedOccluded );
qDebug(" internal : %lu\n", _internalSkippedOccluded );
qDebug(" leaves : %lu\n", _leavesSkippedOccluded );
qDebug(" color sent : %lu\n", _colorSent );
qDebug(" internal : %lu\n", _internalColorSent );
qDebug(" leaves : %lu\n", _leavesColorSent );
qDebug(" Didn't Fit : %lu\n", _didntFit );
qDebug(" internal : %lu\n", _internalDidntFit );
qDebug(" leaves : %lu\n", _leavesDidntFit );
}

View file

@ -11,43 +11,85 @@
#include <stdint.h>
class VoxelNode;
class VoxelSceneStats {
public:
VoxelSceneStats();
~VoxelSceneStats();
void reset();
void sceneStarted();
void sceneStarted(bool fullScene, bool moving);
void sceneCompleted();
void printDebugDetails();
void packetSent(int bytes);
void traversed(const VoxelNode* node);
void skippedDistance(const VoxelNode* node);
void skippedOutOfView(const VoxelNode* node);
void skippedWasInView(const VoxelNode* node);
void skippedNoChange(const VoxelNode* node);
void skippedOccluded(const VoxelNode* node);
void colorSent(const VoxelNode* node);
void didntFit(const VoxelNode* node);
void colorBitsWritten(const VoxelNode* node);
void existsBitsWritten(const VoxelNode* node);
void existsInPacketBitsWritten(const VoxelNode* node);
private:
// scene timing data in usecs
uint64_t start;
uint64_t end;
uint64_t elapsed;
uint64_t _start;
uint64_t _end;
uint64_t _elapsed;
// scene voxel related data
unsigned long _traversed;
unsigned long _internal;
unsigned long _leaves;
unsigned long _skippedDistance;
unsigned long _internalSkippedDistance;
unsigned long _leavesSkippedDistance;
unsigned long _skippedOutOfView;
unsigned long _internalSkippedOutOfView;
unsigned long _leavesSkippedOutOfView;
unsigned long _skippedWasInView;
unsigned long _internalSkippedWasInView;
unsigned long _leavesSkippedWasInView;
unsigned long _skippedNoChange;
unsigned long _internalSkippedNoChange;
unsigned long _leavesSkippedNoChange;
unsigned long _skippedOccluded;
unsigned long _internalSkippedOccluded;
unsigned long _leavesSkippedOccluded;
unsigned long _colorSent;
unsigned long _internalColorSent;
unsigned long _leavesColorSent;
unsigned long _didntFit;
unsigned long _internalDidntFit;
unsigned long _leavesDidntFit;
unsigned long total;
unsigned long traversed;
unsigned long internal;
unsigned long internalOutOfView;
unsigned long internalOccluded;
unsigned long internalDirty;
unsigned long leaves;
unsigned long leavesOutOfView;
unsigned long leavesOccluded;
unsigned long leavesDirty;
// scene network related data
unsigned int packets;
unsigned int bytes;
unsigned int passes;
unsigned int _packets;
unsigned int _bytes;
unsigned int _passes;
// features related items
bool wasFinished;
bool wasMoving;
bool hadDeltaView;
bool hadOcclusionCulling;
bool _moving;
bool _fullSceneDraw;
};
#endif /* defined(__hifi__VoxelSceneStats__) */

View file

@ -1037,6 +1037,13 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer,
availableBytes -= codeLength; // keep track or remaining space
int currentEncodeLevel = 0;
// record some stats, this is the one node that we won't record below in the recursion function, so we need to
// track it here
if (params.stats) {
params.stats->traversed(node);
}
int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, bag, params, currentEncodeLevel);
// if childBytesWritten == 1 then something went wrong... that's not possible
@ -1081,6 +1088,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// If we're too far away for our render level, then just return
if (distance >= boundaryDistance) {
if (params.stats) {
params.stats->skippedDistance(node);
}
return bytesAtThisLevel;
}
@ -1088,6 +1098,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
// we're out of view
if (!node->isInView(*params.viewFrustum)) {
if (params.stats) {
params.stats->skippedOutOfView(node);
}
return bytesAtThisLevel;
}
@ -1110,6 +1123,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do
// need to send it.
if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) {
if (params.stats) {
params.stats->skippedWasInView(node);
}
return bytesAtThisLevel;
}
@ -1117,6 +1133,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// then we can also bail early and save bits
if (!params.forceSendScene && !params.deltaViewFrustum &&
!node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) {
if (params.stats) {
params.stats->skippedNoChange(node);
}
return bytesAtThisLevel;
}
@ -1136,6 +1155,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false);
delete voxelPolygon; // cleanup
if (result == OCCLUDED) {
if (params.stats) {
params.stats->skippedOccluded(node);
}
return bytesAtThisLevel;
}
} else {
@ -1201,6 +1223,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
distancesToChildren[i] = 0.0f;
currentCount++;
}
// track stats
if (params.stats && childNode) {
params.stats->traversed(childNode);
}
}
// for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
@ -1211,13 +1239,21 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum)));
if (childIsInView) {
if (!childIsInView) {
if (params.stats) {
params.stats->skippedOutOfView(childNode);
}
} else {
// Before we determine consider this further, let's see if it's in our LOD scope...
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
float boundaryDistance = !params.viewFrustum ? 1 :
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust);
if (distance < boundaryDistance) {
if (!(distance < boundaryDistance)) {
if (params.stats) {
params.stats->skippedDistance(childNode);
}
} else {
inViewCount++;
// track children in view as existing and not a leaf, if they're a leaf,
@ -1261,7 +1297,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
} // wants occlusion culling & isLeaf()
bool shouldRender = !params.viewFrustum ? true : childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust);
bool shouldRender = !params.viewFrustum ? true :
childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust);
// track some stats
if (params.stats) {
if (!shouldRender) {
params.stats->skippedDistance(childNode);
}
if (childIsOccluded) {
params.stats->skippedOccluded(childNode);
}
}
// track children with actual color, only if the child wasn't previously in view!
if (shouldRender && !childIsOccluded) {
@ -1288,7 +1335,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
inViewWithColorCount++;
} else {
// otherwise just track stats of the items we discarded
params.childWasInViewDiscarded++;
if (params.stats) {
if (childWasInView) {
params.stats->skippedWasInView(childNode);
} else {
params.stats->skippedNoChange(childNode);
}
}
}
}
}
@ -1297,14 +1351,23 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
*writeToThisLevelBuffer = childrenColoredBits;
writeToThisLevelBuffer += sizeof(childrenColoredBits); // move the pointer
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
if (params.stats) {
params.stats->colorBitsWritten(node);
}
// write the color data...
if (params.includeColor) {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (oneAtBit(childrenColoredBits, i)) {
memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR);
VoxelNode* childNode = node->getChildAtIndex(i);
memcpy(writeToThisLevelBuffer, &childNode->getColor(), BYTES_PER_COLOR);
writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color
bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color
if (params.stats) {
params.stats->colorSent(childNode);
}
}
}
}
@ -1315,12 +1378,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
*writeToThisLevelBuffer = childrenExistInTreeBits;
writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer
bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count
if (params.stats) {
params.stats->existsBitsWritten(node);
}
}
// write the child exist bits
*writeToThisLevelBuffer = childrenExistInPacketBits;
writeToThisLevelBuffer += sizeof(childrenExistInPacketBits); // move the pointer
bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count
if (params.stats) {
params.stats->existsInPacketBitsWritten(node);
}
// We only need to keep digging, if there is at least one child that is inView, and not a leaf.
keepDiggingDeeper = (inViewNotLeafCount > 0);
@ -1333,6 +1402,11 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
availableBytes -= bytesAtThisLevel;
} else {
bag.insert(node);
if (params.stats) {
params.stats->didntFit(node);
}
return 0;
}

View file

@ -9,12 +9,14 @@
#ifndef __hifi__VoxelTree__
#define __hifi__VoxelTree__
#include "SimpleMovingAverage.h"
#include <PointerStack.h>
#include <SimpleMovingAverage.h>
#include "CoverageMap.h"
#include "ViewFrustum.h"
#include "VoxelNode.h"
#include "VoxelNodeBag.h"
#include "CoverageMap.h"
#include "PointerStack.h"
#include "VoxelSceneStats.h"
// Callback function, for recuseTreeWithOperation
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
@ -36,6 +38,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define NO_BOUNDARY_ADJUST 0
#define LOW_RES_MOVING_ADJUST 1
#define IGNORE_LAST_SENT 0
#define IGNORE_SCENE_STATS NULL
class EncodeBitstreamParams {
public:
@ -48,10 +51,10 @@ public:
bool deltaViewFrustum;
const ViewFrustum* lastViewFrustum;
bool wantOcclusionCulling;
long childWasInViewDiscarded;
int boundaryLevelAdjust;
uint64_t lastViewFrustumSent;
bool forceSendScene;
VoxelSceneStats* stats;
CoverageMap* map;
EncodeBitstreamParams(
@ -66,7 +69,8 @@ public:
CoverageMap* map = IGNORE_COVERAGE_MAP,
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST,
uint64_t lastViewFrustumSent = IGNORE_LAST_SENT,
bool forceSendScene = true) :
bool forceSendScene = true,
VoxelSceneStats* stats = IGNORE_SCENE_STATS) :
maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0),
viewFrustum (viewFrustum),
@ -76,10 +80,10 @@ public:
deltaViewFrustum (deltaViewFrustum),
lastViewFrustum (lastViewFrustum),
wantOcclusionCulling (wantOcclusionCulling),
childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust),
lastViewFrustumSent (lastViewFrustumSent),
forceSendScene (forceSendScene),
stats (stats),
map (map)
{}
};

View file

@ -200,9 +200,6 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
// only set our last sent time if we weren't resetting due to frustum change
uint64_t now = usecTimestampNow();
nodeData->setLastTimeBagEmpty(now);
if (::debugVoxelSending) {
printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now);
}
}
nodeData->stats.sceneCompleted();
@ -210,7 +207,10 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
// This is the start of "resending" the scene.
nodeData->nodeBag.insert(serverTree.rootNode);
nodeData->stats.sceneStarted();
// start tracking our stats
bool fullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging();
nodeData->stats.sceneStarted(fullScene, viewFrustumChanged);
}
// If we have something in our nodeBag, then turn them into packets and send them out...
@ -243,12 +243,15 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving()
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST;
bool fullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) &&
nodeData->getViewFrustumJustStoppedChanging();
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
nodeData->getLastTimeBagEmpty(),
nodeData->getViewFrustumJustStoppedChanging());
fullScene, &nodeData->stats);
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params);
@ -258,6 +261,8 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
} else {
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
nodeData->stats.packetSent(nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
packetsSentThisInterval++;
@ -268,6 +273,7 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
if (nodeData->isPacketWaiting()) {
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
nodeData->stats.packetSent(nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();