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 | 58 | VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) |
| 59 | 59 | : NodeData(), |
| 60 | − _treeScale(treeScale), | |
| 61 | − _maxVoxels(maxVoxels), | |
| 62 | − _initialized(false) { | |
| 60 | + _treeScale(treeScale), | |
| 61 | + _maxVoxels(maxVoxels), | |
| 62 | + _initialized(false), | |
| 63 | + _writeArraysLock(QReadWriteLock::Recursive), | |
| 64 | + _readArraysLock(QReadWriteLock::Recursive) | |
| 65 | + { | |
| 63 | 66 | |
| 64 | 67 | _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; |
| 65 | 68 | _writeRenderFullVBO = true; |
| @@ -124,8 +127,16 @@ void VoxelSystem::setDisableFastVoxelPipeline(bool disableFastVoxelPipeline) { · 58 unmodified lines | ||
| 124 | 127 | |
| 125 | 128 | void VoxelSystem::elementUpdated(OctreeElement* element) { |
| 126 | 129 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; |
| 130 | +//qDebug() << "VoxelSystem::elementUpdated()..."; | |
| 131 | + | |
| 127 | 132 | // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail.. |
| 128 | 133 | if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { |
| 134 | +/* | |
| 135 | +qDebug() << "VoxelSystem::elementUpdated()... BAILING!!! " | |
| 136 | + << "_writeRenderFullVBO="<< _writeRenderFullVBO | |
| 137 | + << "_inSetupNewVoxelsForDrawing="<< _inSetupNewVoxelsForDrawing | |
| 138 | + << "_useFastVoxelPipeline="<< _useFastVoxelPipeline; | |
| 139 | +*/ | |
| 129 | 140 | return; |
| 130 | 141 | } |
| 131 | 142 | |
| @@ -136,6 +147,8 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 4 unmodified lines | ||
| 136 | 147 | int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); |
| 137 | 148 | shouldRender = voxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); |
| 138 | 149 | |
| 150 | +//qDebug() << "VoxelSystem::elementUpdated()... recalcing should render!!"; | |
| 151 | + | |
| 139 | 152 | if (voxel->getShouldRender() != shouldRender) { |
| 140 | 153 | voxel->setShouldRender(shouldRender); |
| 141 | 154 | } |
| @@ -163,11 +176,13 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 21 unmodified lines | ||
| 163 | 176 | |
| 164 | 177 | const bool REUSE_INDEX = true; |
| 165 | 178 | const bool DONT_FORCE_REDRAW = false; |
| 179 | +//qDebug() << "VoxelSystem::elementUpdated()... calling updateNodeInArrays()!!!"; | |
| 166 | 180 | updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); |
| 167 | 181 | _voxelsUpdated++; |
| 168 | 182 | |
| 169 | 183 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| 170 | 184 | |
| 185 | +//qDebug() << "VoxelSystem::elementUpdated()... calling setupNewVoxelsForDrawingSingleNode()!!!"; | |
| 171 | 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 | 426 | void VoxelSystem::initVoxelMemory() { |
| 412 | − _readArraysLock.lockForWrite(); | |
| 427 | + //_readArraysLock.lockForWrite(); | |
| 428 | + //_writeArraysLock.lockForWrite(); | |
| 413 | 429 | |
| 414 | 430 | _memoryUsageRAM = 0; |
| 415 | 431 | _memoryUsageVBO = 0; // our VBO allocations as we know them |
| @@ -524,7 +540,8 @@ void VoxelSystem::initVoxelMemory() { · 108 unmodified lines | ||
| 524 | 540 | |
| 525 | 541 | _initialized = true; |
| 526 | 542 | |
| 527 | − _readArraysLock.unlock(); | |
| 543 | + //_writeArraysLock.unlock(); | |
| 544 | + //_readArraysLock.unlock(); | |
| 528 | 545 | } |
| 529 | 546 | |
| 530 | 547 | void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const { |
| @@ -741,9 +758,90 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 210 unmodified lines | ||
| 741 | 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 | 815 | void VoxelSystem::recreateVoxelGeometryInView() { |
| 745 | − // this is a temporary solution... we need a full implementation that actually does a full redraw into clean VBOs | |
| 746 | − hideOutOfView(true); | |
| 816 | + | |
| 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 | 847 | void VoxelSystem::checkForCulling() { |
| @@ -784,7 +882,8 @@ void VoxelSystem::checkForCulling() { · 34 unmodified lines | ||
| 784 | 882 | |
| 785 | 883 | if (fullRedraw) { |
| 786 | 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 | 887 | } else { |
| 789 | 888 | hideOutOfView(forceFullFrustum); |
| 790 | 889 | } |
| @@ -905,12 +1004,26 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { · 114 unmodified lines | ||
| 905 | 1004 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 906 | 1005 | "copyWrittenDataToReadArrays()"); |
| 907 | 1006 | |
| 908 | − if (_voxelsDirty && _voxelsUpdated) { | |
| 909 | − if (fullVBOs) { | |
| 910 | − copyWrittenDataToReadArraysFullVBOs(); | |
| 1007 | + // attempt to get the writeArraysLock for reading and the readArraysLock for writing | |
| 1008 | + // so we can copy from the write to the read... if we fail, that's ok, we'll get it the next | |
| 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 | 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 | 1218 | connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); |
| 1106 | 1219 | connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); |
| 1107 | 1220 | |
| 1108 | − setupNewVoxelsForDrawing(); | |
| 1221 | + // TODO: hmmmmm????? | |
| 1222 | + //setupNewVoxelsForDrawing(); | |
| 1109 | 1223 | } |
| 1110 | 1224 | |
| 1111 | 1225 | void VoxelSystem::updateFullVBOs() { |
| @@ -1166,17 +1280,27 @@ void VoxelSystem::updateVBOs() { · 54 unmodified lines | ||
| 1166 | 1280 | // would like to include _callsToTreesToArrays |
| 1167 | 1281 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); |
| 1168 | 1282 | if (_voxelsDirty) { |
| 1169 | − if (_readRenderFullVBO) { | |
| 1170 | − updateFullVBOs(); | |
| 1283 | + | |
| 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 | 1296 | } else { |
| 1172 | − updatePartialVBOs(); | |
| 1297 | + qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()"; | |
| 1173 | 1298 | } |
| 1174 | − _voxelsDirty = false; | |
| 1175 | − _readRenderFullVBO = false; | |
| 1176 | 1299 | } |
| 1177 | 1300 | _callsToTreesToArrays = 0; // clear it |
| 1178 | 1301 | } |
| 1179 | 1302 | |
| 1303 | +// this should only be called on the main application thread during render | |
| 1180 | 1304 | void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { |
| 1181 | 1305 | bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1182 | 1306 | PerformanceWarning warn(showWarning, "updateVBOSegment()"); |