Showing the changes to interface/src/VoxelSystem.cpp (1 of 2 files). Show all
Unified · Split
| @@ -57,9 +57,12 @@ GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 }; · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) | 58 | VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) |
| 59 | : NodeData(), | 59 | : NodeData(), |
| 60 | _treeScale(treeScale), | 60 | _treeScale(treeScale), |
| 61 | _maxVoxels(maxVoxels), | 61 | _maxVoxels(maxVoxels), |
| 62 | _initialized(false) { | 62 | _initialized(false), |
| 63 | _writeArraysLock(QReadWriteLock::Recursive), | ||
| 64 | _readArraysLock(QReadWriteLock::Recursive) | ||
| 65 | { | ||
| 63 | 66 | ||
| 64 | _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; | 67 | _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; |
| 65 | _writeRenderFullVBO = true; | 68 | _writeRenderFullVBO = true; |
| @@ -124,8 +127,16 @@ void VoxelSystem::setDisableFastVoxelPipeline(bool disableFastVoxelPipeline) { · 58 unmodified lines | |||
| 124 | 127 | ||
| 125 | void VoxelSystem::elementUpdated(OctreeElement* element) { | 128 | void VoxelSystem::elementUpdated(OctreeElement* element) { |
| 126 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | 129 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; |
| 130 | //qDebug() << "VoxelSystem::elementUpdated()..."; | ||
| 131 | |||
| 127 | // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail.. | 132 | // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail.. |
| 128 | if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { | 133 | if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { |
| 134 | /* | ||
| 135 | qDebug() << "VoxelSystem::elementUpdated()... BAILING!!! " | ||
| 136 | << "_writeRenderFullVBO="<< _writeRenderFullVBO | ||
| 137 | << "_inSetupNewVoxelsForDrawing="<< _inSetupNewVoxelsForDrawing | ||
| 138 | << "_useFastVoxelPipeline="<< _useFastVoxelPipeline; | ||
| 139 | */ | ||
| 129 | return; | 140 | return; |
| 130 | } | 141 | } |
| 131 | 142 | ||
| @@ -136,6 +147,8 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 4 unmodified lines | |||
| 136 | int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); | 147 | int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); |
| 137 | shouldRender = voxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); | 148 | shouldRender = voxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); |
| 138 | 149 | ||
| 150 | //qDebug() << "VoxelSystem::elementUpdated()... recalcing should render!!"; | ||
| 151 | |||
| 139 | if (voxel->getShouldRender() != shouldRender) { | 152 | if (voxel->getShouldRender() != shouldRender) { |
| 140 | voxel->setShouldRender(shouldRender); | 153 | voxel->setShouldRender(shouldRender); |
| 141 | } | 154 | } |
| @@ -163,11 +176,13 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 21 unmodified lines | |||
| 163 | 176 | ||
| 164 | const bool REUSE_INDEX = true; | 177 | const bool REUSE_INDEX = true; |
| 165 | const bool DONT_FORCE_REDRAW = false; | 178 | const bool DONT_FORCE_REDRAW = false; |
| 179 | //qDebug() << "VoxelSystem::elementUpdated()... calling updateNodeInArrays()!!!"; | ||
| 166 | updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); | 180 | updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); |
| 167 | _voxelsUpdated++; | 181 | _voxelsUpdated++; |
| 168 | 182 | ||
| 169 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. | 183 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| 170 | 184 | ||
| 185 | //qDebug() << "VoxelSystem::elementUpdated()... calling setupNewVoxelsForDrawingSingleNode()!!!"; | ||
| 171 | setupNewVoxelsForDrawingSingleNode(); | 186 | setupNewVoxelsForDrawingSingleNode(); |
| 172 | } | 187 | } |
| 173 | } | 188 | } |
| @@ -409,7 +424,8 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice · 235 unmodified lines | |||
| 409 | } | 424 | } |
| 410 | 425 | ||
| 411 | void VoxelSystem::initVoxelMemory() { | 426 | void VoxelSystem::initVoxelMemory() { |
| 412 | _readArraysLock.lockForWrite(); | 427 | //_readArraysLock.lockForWrite(); |
| 428 | //_writeArraysLock.lockForWrite(); | ||
| 413 | 429 | ||
| 414 | _memoryUsageRAM = 0; | 430 | _memoryUsageRAM = 0; |
| 415 | _memoryUsageVBO = 0; // our VBO allocations as we know them | 431 | _memoryUsageVBO = 0; // our VBO allocations as we know them |
| @@ -524,7 +540,8 @@ void VoxelSystem::initVoxelMemory() { · 108 unmodified lines | |||
| 524 | 540 | ||
| 525 | _initialized = true; | 541 | _initialized = true; |
| 526 | 542 | ||
| 527 | _readArraysLock.unlock(); | 543 | //_writeArraysLock.unlock(); |
| 544 | //_readArraysLock.unlock(); | ||
| 528 | } | 545 | } |
| 529 | 546 | ||
| 530 | void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const { | 547 | void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const { |
| @@ -741,9 +758,90 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 210 unmodified lines | |||
| 741 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; | 758 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; |
| 742 | } | 759 | } |
| 743 | 760 | ||
| 761 | |||
| 762 | |||
| 763 | class recreateVoxelGeometryInViewArgs { | ||
| 764 | public: | ||
| 765 | VoxelSystem* thisVoxelSystem; | ||
| 766 | ViewFrustum thisViewFrustum; | ||
| 767 | unsigned long nodesScanned; | ||
| 768 | float voxelSizeScale; | ||
| 769 | int boundaryLevelAdjust; | ||
| 770 | |||
| 771 | recreateVoxelGeometryInViewArgs(VoxelSystem* voxelSystem) : | ||
| 772 | thisVoxelSystem(voxelSystem), | ||
| 773 | thisViewFrustum(*voxelSystem->getViewFrustum()), | ||
| 774 | nodesScanned(0), | ||
| 775 | voxelSizeScale(Menu::getInstance()->getVoxelSizeScale()), | ||
| 776 | boundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust()) | ||
| 777 | { | ||
| 778 | } | ||
| 779 | }; | ||
| 780 | |||
| 781 | // The goal of this operation is to remove any old references to old geometry, and if the voxel | ||
| 782 | // should be visible, create new geometry for it. | ||
| 783 | bool VoxelSystem::recreateVoxelGeometryInViewOperation(OctreeElement* element, void* extraData) { | ||
| 784 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 785 | recreateVoxelGeometryInViewArgs* args = (recreateVoxelGeometryInViewArgs*)extraData; | ||
| 786 | |||
| 787 | args->nodesScanned++; | ||
| 788 | |||
| 789 | // reset the old geometry... | ||
| 790 | // note: this doesn't "mark the voxel as changed", so it only releases the old buffer index thereby forgetting the | ||
| 791 | // old geometry | ||
| 792 | voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); | ||
| 793 | |||
| 794 | bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, args->voxelSizeScale, args->boundaryLevelAdjust); | ||
| 795 | bool inView = voxel->isInView(args->thisViewFrustum); | ||
| 796 | voxel->setShouldRender(inView && shouldRender); | ||
| 797 | |||
| 798 | if (shouldRender) { | ||
| 799 | bool falseColorize = false; | ||
| 800 | if (falseColorize) { | ||
| 801 | voxel->setFalseColor(0,0,255); // false colorize | ||
| 802 | } | ||
| 803 | // These are both needed to force redraw... | ||
| 804 | voxel->setDirtyBit(); | ||
| 805 | qDebug() << "recreateVoxelGeometryInViewOperation()... calling voxel->markWithChangedTime()"; | ||
| 806 | voxel->markWithChangedTime(); // this will notifyUpdateHooks, which will result in our geometry being created | ||
| 807 | } | ||
| 808 | |||
| 809 | return true; // keep recursing! | ||
| 810 | } | ||
| 811 | |||
| 812 | |||
| 813 | // TODO: does cleanupRemovedVoxels() ever get called? | ||
| 814 | // TODO: other than cleanupRemovedVoxels() is there anyplace we attempt to detect too many abandoned slots??? | ||
| 744 | void VoxelSystem::recreateVoxelGeometryInView() { | 815 | void VoxelSystem::recreateVoxelGeometryInView() { |
| 745 | // this is a temporary solution... we need a full implementation that actually does a full redraw into clean VBOs | 816 | |
| 746 | hideOutOfView(true); | 817 | qDebug() << "recreateVoxelGeometryInView()..."; |
| 818 | |||
| 819 | recreateVoxelGeometryInViewArgs args(this); | ||
| 820 | _writeArraysLock.lockForWrite(); // don't let anyone read or write our write arrays until we're done | ||
| 821 | _tree->lockForRead(); // don't let anyone change our tree structure until we're run | ||
| 822 | |||
| 823 | // reset our write arrays bookkeeping to think we've got no voxels in it | ||
| 824 | clearFreeBufferIndexes(); // does this do everything we need? | ||
| 825 | /** | ||
| 826 | // clear out all our abandoned indexes - they are all available | ||
| 827 | // TODO: is it possible freeBufferIndex() will get called??? | ||
| 828 | _voxelsInWriteArrays = 0; | ||
| 829 | _freeIndexLock.lock(); | ||
| 830 | _freeIndexes.clear(); | ||
| 831 | _freeIndexLock.unlock(); | ||
| 832 | **/ | ||
| 833 | |||
| 834 | //_voxelsUpdated = 0; // ???? | ||
| 835 | //_writeRenderFullVBO = true; | ||
| 836 | |||
| 837 | // do we need to reset out _writeVoxelDirtyArray arrays?? | ||
| 838 | memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); | ||
| 839 | |||
| 840 | |||
| 841 | |||
| 842 | _tree->recurseTreeWithOperation(recreateVoxelGeometryInViewOperation,(void*)&args); | ||
| 843 | _tree->unlock(); | ||
| 844 | _writeArraysLock.unlock(); | ||
| 747 | } | 845 | } |
| 748 | 846 | ||
| 749 | void VoxelSystem::checkForCulling() { | 847 | void VoxelSystem::checkForCulling() { |
| @@ -784,7 +882,8 @@ void VoxelSystem::checkForCulling() { · 34 unmodified lines | |||
| 784 | 882 | ||
| 785 | if (fullRedraw) { | 883 | if (fullRedraw) { |
| 786 | // this will remove all old geometry and recreate the correct geometry for all in view voxels | 884 | // this will remove all old geometry and recreate the correct geometry for all in view voxels |
| 787 | recreateVoxelGeometryInView(); | 885 | //recreateVoxelGeometryInView(); |
| 886 | hideOutOfView(forceFullFrustum); | ||
| 788 | } else { | 887 | } else { |
| 789 | hideOutOfView(forceFullFrustum); | 888 | hideOutOfView(forceFullFrustum); |
| 790 | } | 889 | } |
| @@ -905,12 +1004,26 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { · 114 unmodified lines | |||
| 905 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | 1004 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 906 | "copyWrittenDataToReadArrays()"); | 1005 | "copyWrittenDataToReadArrays()"); |
| 907 | 1006 | ||
| 908 | if (_voxelsDirty && _voxelsUpdated) { | 1007 | // attempt to get the writeArraysLock for reading and the readArraysLock for writing |
| 909 | if (fullVBOs) { | 1008 | // so we can copy from the write to the read... if we fail, that's ok, we'll get it the next |
| 910 | copyWrittenDataToReadArraysFullVBOs(); | 1009 | // time around, the only side effect is the VBOs won't be updated this frame |
| 1010 | const int WAIT_FOR_LOCK_IN_MS = 5; | ||
| 1011 | if (_readArraysLock.tryLockForWrite(WAIT_FOR_LOCK_IN_MS)) { | ||
| 1012 | if (_writeArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { | ||
| 1013 | if (_voxelsDirty && _voxelsUpdated) { | ||
| 1014 | if (fullVBOs) { | ||
| 1015 | copyWrittenDataToReadArraysFullVBOs(); | ||
| 1016 | } else { | ||
| 1017 | copyWrittenDataToReadArraysPartialVBOs(); | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | _writeArraysLock.unlock(); | ||
| 911 | } else { | 1021 | } else { |
| 912 | copyWrittenDataToReadArraysPartialVBOs(); | 1022 | qDebug() << "couldn't get _writeArraysLock.LockForRead()..."; |
| 913 | } | 1023 | } |
| 1024 | _readArraysLock.unlock(); | ||
| 1025 | } else { | ||
| 1026 | qDebug() << "couldn't get _readArraysLock.LockForWrite()..."; | ||
| 914 | } | 1027 | } |
| 915 | } | 1028 | } |
| 916 | 1029 | ||
| @@ -1105,7 +1218,8 @@ void VoxelSystem::changeTree(VoxelTree* newTree) { · 188 unmodified lines | |||
| 1105 | connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); | 1218 | connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); |
| 1106 | connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); | 1219 | connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); |
| 1107 | 1220 | ||
| 1108 | setupNewVoxelsForDrawing(); | 1221 | // TODO: hmmmmm????? |
| 1222 | //setupNewVoxelsForDrawing(); | ||
| 1109 | } | 1223 | } |
| 1110 | 1224 | ||
| 1111 | void VoxelSystem::updateFullVBOs() { | 1225 | void VoxelSystem::updateFullVBOs() { |
| @@ -1166,17 +1280,27 @@ void VoxelSystem::updateVBOs() { · 54 unmodified lines | |||
| 1166 | // would like to include _callsToTreesToArrays | 1280 | // would like to include _callsToTreesToArrays |
| 1167 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); | 1281 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); |
| 1168 | if (_voxelsDirty) { | 1282 | if (_voxelsDirty) { |
| 1169 | if (_readRenderFullVBO) { | 1283 | |
| 1170 | updateFullVBOs(); | 1284 | // attempt to lock the read arrays, to for copying from them to the actual GPU VBOs. |
| 1285 | // if we fail to get the lock, that's ok, our VBOs will update on the next frame... | ||
| 1286 | const int WAIT_FOR_LOCK_IN_MS = 5; | ||
| 1287 | if (_readArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { | ||
| 1288 | if (_readRenderFullVBO) { | ||
| 1289 | updateFullVBOs(); | ||
| 1290 | } else { | ||
| 1291 | updatePartialVBOs(); | ||
| 1292 | } | ||
| 1293 | _voxelsDirty = false; | ||
| 1294 | _readRenderFullVBO = false; | ||
| 1295 | _readArraysLock.unlock(); | ||
| 1171 | } else { | 1296 | } else { |
| 1172 | updatePartialVBOs(); | 1297 | qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()"; |
| 1173 | } | 1298 | } |
| 1174 | _voxelsDirty = false; | ||
| 1175 | _readRenderFullVBO = false; | ||
| 1176 | } | 1299 | } |
| 1177 | _callsToTreesToArrays = 0; // clear it | 1300 | _callsToTreesToArrays = 0; // clear it |
| 1178 | } | 1301 | } |
| 1179 | 1302 | ||
| 1303 | // this should only be called on the main application thread during render | ||
| 1180 | void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { | 1304 | void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { |
| 1181 | bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 1305 | bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1182 | PerformanceWarning warn(showWarning, "updateVBOSegment()"); | 1306 | PerformanceWarning warn(showWarning, "updateVBOSegment()"); |