Showing the changes to interface/src/VoxelSystem.cpp (1 of 2 files). Show all
Unified · Split
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <fstream> // to load voxels from file | 15 | #include <fstream> // to load voxels from file |
| 16 | #include <SharedUtil.h> | 16 | #include <SharedUtil.h> |
| 17 | #include <PacketHeaders.h> | 17 | #include <PacketHeaders.h> |
| 18 | #include <PerfStat.h> | ||
| 18 | #include <OctalCode.h> | 19 | #include <OctalCode.h> |
| 19 | #include <pthread.h> | 20 | #include <pthread.h> |
| 20 | #include "Log.h" | 21 | #include "Log.h" |
| @@ -44,6 +45,7 @@ VoxelSystem::VoxelSystem() { · 23 unmodified lines | |||
| 44 | _voxelsInArrays = _voxelsUpdated = 0; | 45 | _voxelsInArrays = _voxelsUpdated = 0; |
| 45 | _tree = new VoxelTree(); | 46 | _tree = new VoxelTree(); |
| 46 | pthread_mutex_init(&_bufferWriteLock, NULL); | 47 | pthread_mutex_init(&_bufferWriteLock, NULL); |
| 48 | pthread_mutex_init(&_voxelCleanupLock, NULL); | ||
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | VoxelSystem::~VoxelSystem() { | 51 | VoxelSystem::~VoxelSystem() { |
| @@ -54,6 +56,7 @@ VoxelSystem::~VoxelSystem() { · 4 unmodified lines | |||
| 54 | delete[] _voxelDirtyArray; | 56 | delete[] _voxelDirtyArray; |
| 55 | delete _tree; | 57 | delete _tree; |
| 56 | pthread_mutex_destroy(&_bufferWriteLock); | 58 | pthread_mutex_destroy(&_bufferWriteLock); |
| 59 | pthread_mutex_destroy(&_voxelCleanupLock); | ||
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { | 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 | switch(command) { | 101 | switch(command) { |
| 99 | case PACKET_HEADER_VOXEL_DATA: | 102 | case PACKET_HEADER_VOXEL_DATA: |
| 100 | { | 103 | { |
| 101 | double start = usecTimestampNow(); | 104 | PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); |
| 102 | // ask the VoxelTree to read the bitstream into the tree | 105 | // ask the VoxelTree to read the bitstream into the tree |
| 103 | _tree->readBitstreamToTree(voxelData, numBytes - 1); | 106 | _tree->readBitstreamToTree(voxelData, numBytes - 1); |
| 104 | if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) { | 107 | if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) { |
| 105 | printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n", | 108 | printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n", |
| 106 | _tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") ); | 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 | break; | 112 | break; |
| 121 | case PACKET_HEADER_ERASE_VOXEL: | 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 | void VoxelSystem::setupNewVoxelsForDrawing() { | 147 | void VoxelSystem::setupNewVoxelsForDrawing() { |
| 148 | PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated | ||
| 156 | double start = usecTimestampNow(); | 149 | double start = usecTimestampNow(); |
| 157 | |||
| 158 | double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); | 150 | double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); |
| 159 | 151 | ||
| 160 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { | 152 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { |
| 161 | return; // bail early, it hasn't been long enough since the last time we ran | 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 | if (_tree->isDirty()) { | 161 | if (_tree->isDirty()) { |
| 165 | _callsToTreesToArrays++; | 162 | _callsToTreesToArrays++; |
| 166 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); | 163 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); |
| @@ -179,21 +176,12 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 12 unmodified lines | |||
| 179 | 176 | ||
| 180 | double end = usecTimestampNow(); | 177 | double end = usecTimestampNow(); |
| 181 | double elapsedmsec = (end - start)/1000.0; | 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 | _setupNewVoxelsForDrawingLastFinished = end; | 179 | _setupNewVoxelsForDrawingLastFinished = end; |
| 192 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; | 180 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; |
| 193 | } | 181 | } |
| 194 | 182 | ||
| 195 | void VoxelSystem::copyWrittenDataToReadArrays() { | 183 | void VoxelSystem::copyWrittenDataToReadArrays() { |
| 196 | double start = usecTimestampNow(); | 184 | PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated |
| 197 | if (_voxelsDirty && _voxelsUpdated) { | 185 | if (_voxelsDirty && _voxelsUpdated) { |
| 198 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it | 186 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 199 | pthread_mutex_lock(&_bufferWriteLock); | 187 | pthread_mutex_lock(&_bufferWriteLock); |
| @@ -203,18 +191,6 @@ void VoxelSystem::copyWrittenDataToReadArrays() { · 3 unmodified lines | |||
| 203 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); | 191 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); |
| 204 | pthread_mutex_unlock(&_bufferWriteLock); | 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 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { | 196 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { |
| @@ -301,6 +277,7 @@ void VoxelSystem::init() { · 80 unmodified lines | |||
| 301 | // When we change voxels representations in the arrays, we'll update this | 277 | // When we change voxels representations in the arrays, we'll update this |
| 302 | _voxelsDirty = false; | 278 | _voxelsDirty = false; |
| 303 | _voxelsInArrays = 0; | 279 | _voxelsInArrays = 0; |
| 280 | _unusedArraySpace = 0; | ||
| 304 | 281 | ||
| 305 | // we will track individual dirty sections with this array of bools | 282 | // we will track individual dirty sections with this array of bools |
| 306 | _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; | 283 | _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; |
| @@ -369,7 +346,7 @@ void VoxelSystem::init() { · 62 unmodified lines | |||
| 369 | } | 346 | } |
| 370 | 347 | ||
| 371 | void VoxelSystem::updateVBOs() { | 348 | void VoxelSystem::updateVBOs() { |
| 372 | double start = usecTimestampNow(); | 349 | PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays |
| 373 | if (_voxelsDirty) { | 350 | if (_voxelsDirty) { |
| 374 | glBufferIndex segmentStart = 0; | 351 | glBufferIndex segmentStart = 0; |
| 375 | glBufferIndex segmentEnd = 0; | 352 | glBufferIndex segmentEnd = 0; |
| @@ -401,28 +378,13 @@ void VoxelSystem::updateVBOs() { · 25 unmodified lines | |||
| 401 | } | 378 | } |
| 402 | _voxelsDirty = false; | 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 | _callsToTreesToArrays = 0; // clear it | 381 | _callsToTreesToArrays = 0; // clear it |
| 421 | } | 382 | } |
| 422 | 383 | ||
| 423 | void VoxelSystem::render() { | 384 | void VoxelSystem::render() { |
| 424 | double start = usecTimestampNow(); | 385 | PerformanceWarning warn(_renderWarningsOn, "render()"); |
| 425 | glPushMatrix(); | 386 | glPushMatrix(); |
| 387 | //cleanupRemovedVoxels(); | ||
| 426 | updateVBOs(); | 388 | updateVBOs(); |
| 427 | // tell OpenGL where to find vertex and color information | 389 | // tell OpenGL where to find vertex and color information |
| 428 | glEnableClientState(GL_VERTEX_ARRAY); | 390 | glEnableClientState(GL_VERTEX_ARRAY); |
| @@ -454,16 +416,6 @@ void VoxelSystem::render() { · 25 unmodified lines | |||
| 454 | 416 | ||
| 455 | // scale back down to 1 so heads aren't massive | 417 | // scale back down to 1 so heads aren't massive |
| 456 | glPopMatrix(); | 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 | int VoxelSystem::_nodeCount = 0; | 421 | int VoxelSystem::_nodeCount = 0; |
| @@ -591,4 +543,63 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { · 121 unmodified lines | |||
| 591 | setupNewVoxelsForDrawing(); | 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 | } | ||