Showing the changes to interface/src/VoxelSystem.cpp (1 of 2 files). Show all
Unified · Split
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <fstream> // to load voxels from file |
| 16 | 16 | #include <SharedUtil.h> |
| 17 | 17 | #include <PacketHeaders.h> |
| 18 | +#include <PerfStat.h> | |
| 18 | 19 | #include <OctalCode.h> |
| 19 | 20 | #include <pthread.h> |
| 20 | 21 | #include "Log.h" |
| @@ -44,6 +45,7 @@ VoxelSystem::VoxelSystem() { · 23 unmodified lines | ||
| 44 | 45 | _voxelsInArrays = _voxelsUpdated = 0; |
| 45 | 46 | _tree = new VoxelTree(); |
| 46 | 47 | pthread_mutex_init(&_bufferWriteLock, NULL); |
| 48 | + pthread_mutex_init(&_voxelCleanupLock, NULL); | |
| 47 | 49 | } |
| 48 | 50 | |
| 49 | 51 | VoxelSystem::~VoxelSystem() { |
| @@ -54,6 +56,7 @@ VoxelSystem::~VoxelSystem() { · 4 unmodified lines | ||
| 54 | 56 | delete[] _voxelDirtyArray; |
| 55 | 57 | delete _tree; |
| 56 | 58 | pthread_mutex_destroy(&_bufferWriteLock); |
| 59 | + pthread_mutex_destroy(&_voxelCleanupLock); | |
| 57 | 60 | } |
| 58 | 61 | |
| 59 | 62 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { |
| @@ -98,24 +101,13 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 38 unmodified lines | ||
| 98 | 101 | switch(command) { |
| 99 | 102 | case PACKET_HEADER_VOXEL_DATA: |
| 100 | 103 | { |
| 101 | − double start = usecTimestampNow(); | |
| 104 | + PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); | |
| 102 | 105 | // ask the VoxelTree to read the bitstream into the tree |
| 103 | 106 | _tree->readBitstreamToTree(voxelData, numBytes - 1); |
| 104 | 107 | if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) { |
| 105 | 108 | printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n", |
| 106 | 109 | _tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") ); |
| 107 | 110 | } |
| 108 | − | |
| 109 | − double end = usecTimestampNow(); | |
| 110 | − double elapsedmsec = (end - start)/1000.0; | |
| 111 | − if (_renderWarningsOn && elapsedmsec > 1) { | |
| 112 | − if (elapsedmsec > 1000) { | |
| 113 | − double elapsedsec = (end - start)/1000000.0; | |
| 114 | − printLog("WARNING! readBitstreamToTree() took %lf seconds\n",elapsedsec); | |
| 115 | − } else { | |
| 116 | − printLog("WARNING! readBitstreamToTree() took %lf milliseconds\n",elapsedmsec); | |
| 117 | − } | |
| 118 | − } | |
| 119 | 111 | } |
| 120 | 112 | break; |
| 121 | 113 | case PACKET_HEADER_ERASE_VOXEL: |
| @@ -153,14 +145,19 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 31 unmodified lines | ||
| 153 | 145 | } |
| 154 | 146 | |
| 155 | 147 | void VoxelSystem::setupNewVoxelsForDrawing() { |
| 148 | + PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated | |
| 156 | 149 | double start = usecTimestampNow(); |
| 157 | − | |
| 158 | 150 | double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); |
| 159 | 151 | |
| 160 | 152 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { |
| 161 | 153 | return; // bail early, it hasn't been long enough since the last time we ran |
| 162 | 154 | } |
| 163 | 155 | |
| 156 | + // If the view frustum has changed, since last time, then remove nodes that are out of view | |
| 157 | + //if (hasViewChanged()) { | |
| 158 | + // removeOutOfView(); | |
| 159 | + //} | |
| 160 | + | |
| 164 | 161 | if (_tree->isDirty()) { |
| 165 | 162 | _callsToTreesToArrays++; |
| 166 | 163 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); |
| @@ -179,21 +176,12 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 12 unmodified lines | ||
| 179 | 176 | |
| 180 | 177 | double end = usecTimestampNow(); |
| 181 | 178 | double elapsedmsec = (end - start)/1000.0; |
| 182 | − if (_renderWarningsOn && elapsedmsec > 1) { | |
| 183 | − if (elapsedmsec > 1000) { | |
| 184 | − double elapsedsec = (end - start)/1000000.0; | |
| 185 | − printLog("WARNING! newTreeToArrays() took %lf seconds %ld voxels updated\n", elapsedsec, _voxelsUpdated); | |
| 186 | − } else { | |
| 187 | − printLog("WARNING! newTreeToArrays() took %lf milliseconds %ld voxels updated\n", elapsedmsec, _voxelsUpdated); | |
| 188 | − } | |
| 189 | − } | |
| 190 | − | |
| 191 | 179 | _setupNewVoxelsForDrawingLastFinished = end; |
| 192 | 180 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; |
| 193 | 181 | } |
| 194 | 182 | |
| 195 | 183 | void VoxelSystem::copyWrittenDataToReadArrays() { |
| 196 | − double start = usecTimestampNow(); | |
| 184 | + PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated | |
| 197 | 185 | if (_voxelsDirty && _voxelsUpdated) { |
| 198 | 186 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 199 | 187 | pthread_mutex_lock(&_bufferWriteLock); |
| @@ -203,18 +191,6 @@ void VoxelSystem::copyWrittenDataToReadArrays() { · 3 unmodified lines | ||
| 203 | 191 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); |
| 204 | 192 | pthread_mutex_unlock(&_bufferWriteLock); |
| 205 | 193 | } |
| 206 | − double end = usecTimestampNow(); | |
| 207 | − double elapsedmsec = (end - start)/1000.0; | |
| 208 | − if (_renderWarningsOn && elapsedmsec > 1) { | |
| 209 | − if (elapsedmsec > 1000) { | |
| 210 | − double elapsedsec = (end - start)/1000000.0; | |
| 211 | − printLog("WARNING! copyWrittenDataToReadArrays() took %lf seconds for %ld voxels %ld updated\n", | |
| 212 | − elapsedsec, _voxelsInArrays, _voxelsUpdated); | |
| 213 | − } else { | |
| 214 | − printLog("WARNING! copyWrittenDataToReadArrays() took %lf milliseconds for %ld voxels %ld updated\n", | |
| 215 | − elapsedmsec, _voxelsInArrays, _voxelsUpdated); | |
| 216 | − } | |
| 217 | − } | |
| 218 | 194 | } |
| 219 | 195 | |
| 220 | 196 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { |
| @@ -301,6 +277,7 @@ void VoxelSystem::init() { · 80 unmodified lines | ||
| 301 | 277 | // When we change voxels representations in the arrays, we'll update this |
| 302 | 278 | _voxelsDirty = false; |
| 303 | 279 | _voxelsInArrays = 0; |
| 280 | + _unusedArraySpace = 0; | |
| 304 | 281 | |
| 305 | 282 | // we will track individual dirty sections with this array of bools |
| 306 | 283 | _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; |
| @@ -369,7 +346,7 @@ void VoxelSystem::init() { · 62 unmodified lines | ||
| 369 | 346 | } |
| 370 | 347 | |
| 371 | 348 | void VoxelSystem::updateVBOs() { |
| 372 | − double start = usecTimestampNow(); | |
| 349 | + PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays | |
| 373 | 350 | if (_voxelsDirty) { |
| 374 | 351 | glBufferIndex segmentStart = 0; |
| 375 | 352 | glBufferIndex segmentEnd = 0; |
| @@ -401,28 +378,13 @@ void VoxelSystem::updateVBOs() { · 25 unmodified lines | ||
| 401 | 378 | } |
| 402 | 379 | _voxelsDirty = false; |
| 403 | 380 | } |
| 404 | − double end = usecTimestampNow(); | |
| 405 | − double elapsedmsec = (end - start)/1000.0; | |
| 406 | − if (_renderWarningsOn && elapsedmsec > 1) { | |
| 407 | − if (elapsedmsec > 1) { | |
| 408 | − if (elapsedmsec > 1000) { | |
| 409 | − double elapsedsec = (end - start)/1000000.0; | |
| 410 | − printLog("WARNING! updateVBOs() took %lf seconds after %d calls to newTreeToArrays()\n", | |
| 411 | − elapsedsec, _callsToTreesToArrays); | |
| 412 | − } else { | |
| 413 | − printLog("WARNING! updateVBOs() took %lf milliseconds after %d calls to newTreeToArrays()\n", | |
| 414 | − elapsedmsec, _callsToTreesToArrays); | |
| 415 | − } | |
| 416 | − } else { | |
| 417 | − printLog("WARNING! updateVBOs() called after %d calls to newTreeToArrays()\n",_callsToTreesToArrays); | |
| 418 | − } | |
| 419 | − } | |
| 420 | 381 | _callsToTreesToArrays = 0; // clear it |
| 421 | 382 | } |
| 422 | 383 | |
| 423 | 384 | void VoxelSystem::render() { |
| 424 | − double start = usecTimestampNow(); | |
| 385 | + PerformanceWarning warn(_renderWarningsOn, "render()"); | |
| 425 | 386 | glPushMatrix(); |
| 387 | + //cleanupRemovedVoxels(); | |
| 426 | 388 | updateVBOs(); |
| 427 | 389 | // tell OpenGL where to find vertex and color information |
| 428 | 390 | glEnableClientState(GL_VERTEX_ARRAY); |
| @@ -454,16 +416,6 @@ void VoxelSystem::render() { · 25 unmodified lines | ||
| 454 | 416 | |
| 455 | 417 | // scale back down to 1 so heads aren't massive |
| 456 | 418 | glPopMatrix(); |
| 457 | − double end = usecTimestampNow(); | |
| 458 | − double elapsedmsec = (end - start)/1000.0; | |
| 459 | − if (_renderWarningsOn && elapsedmsec > 1) { | |
| 460 | − if (elapsedmsec > 1000) { | |
| 461 | − double elapsedsec = (end - start)/1000000.0; | |
| 462 | − printLog("WARNING! render() took %lf seconds\n",elapsedsec); | |
| 463 | − } else { | |
| 464 | − printLog("WARNING! render() took %lf milliseconds\n",elapsedmsec); | |
| 465 | − } | |
| 466 | − } | |
| 467 | 419 | } |
| 468 | 420 | |
| 469 | 421 | int VoxelSystem::_nodeCount = 0; |
| @@ -591,4 +543,63 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { · 121 unmodified lines | ||
| 591 | 543 | setupNewVoxelsForDrawing(); |
| 592 | 544 | } |
| 593 | 545 | |
| 546 | +// "Remove" voxels from the tree that are not in view. We don't actually delete them, | |
| 547 | +// we remove them from the tree and place them into a holding area for later deletion | |
| 548 | +int removedCount; | |
| 549 | +bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { | |
| 550 | + VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; | |
| 551 | + _nodeCount++; | |
| 552 | + // Need to operate on our child nodes, so we can remove them | |
| 553 | + for (int i = 0; i < 8; i++) { | |
| 554 | + VoxelNode* childNode = node->getChildAtIndex(i); | |
| 555 | + if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { | |
| 556 | + node->removeChildAtIndex(i); | |
| 557 | + removedCount++; | |
| 558 | + | |
| 559 | + // Note: VoxelNodeBag is more expensive than we need, because it checks octal code matches, | |
| 560 | + // we really just want a simple bag that checks pointers only, consider switching | |
| 561 | + thisVoxelSystem->_removedVoxels.insert(childNode); | |
| 562 | + } | |
| 563 | + } | |
| 564 | + return true; // keep going! | |
| 565 | +} | |
| 594 | 566 | |
| 567 | +bool VoxelSystem::hasViewChanged() { | |
| 568 | + bool result = false; // assume the best | |
| 569 | + if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) { | |
| 570 | + result = true; | |
| 571 | + _lastKnowViewFrustum = *_viewFrustum; // save last known | |
| 572 | + } | |
| 573 | + return result; | |
| 574 | +} | |
| 575 | + | |
| 576 | +void VoxelSystem::removeOutOfView() { | |
| 577 | + PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() | |
| 578 | + pthread_mutex_lock(&_voxelCleanupLock); | |
| 579 | + _nodeCount = 0; | |
| 580 | + removedCount = 0; | |
| 581 | + _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); | |
| 582 | + pthread_mutex_unlock(&_voxelCleanupLock); | |
| 583 | +} | |
| 584 | + | |
| 585 | +// Deletes the VoxelNodes from the _removedVoxels bag, but also cleans up those items from the vertex arrays | |
| 586 | +void VoxelSystem::cleanupRemovedVoxels() { | |
| 587 | + if (!pthread_mutex_trylock(&_voxelCleanupLock)) { | |
| 588 | + while (!_removedVoxels.isEmpty()){ | |
| 589 | + VoxelNode* node = _removedVoxels.extract(); | |
| 590 | + // If the voxel is in the vertex, and it was previously rendered, then set it's vertices to "hidden" | |
| 591 | + if (node->isKnownBufferIndex() && node->getShouldRender()) { | |
| 592 | + unsigned long nodeIndex = node->getBufferIndex(); | |
| 593 | + _voxelDirtyArray[nodeIndex] = true; | |
| 594 | + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { | |
| 595 | + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); | |
| 596 | + *(writeVerticesAt+j) = FLT_MAX; | |
| 597 | + } | |
| 598 | + _voxelsDirty = true; // yep | |
| 599 | + } | |
| 600 | + _unusedArraySpace++; // track this so we can blow away our arrays if they get too much | |
| 601 | + delete node; // actually delete the node | |
| 602 | + } | |
| 603 | + pthread_mutex_unlock(&_voxelCleanupLock); | |
| 604 | + } | |
| 605 | +} | |