History

Merge and resolve conflicts of remote-tracking branch 'upstream/master'

matsukaze committed 12 years ago

Commit 8aa645b2 parents b838833 6e1514380 files · +2902 −779Browse files

Showing the changes to interface/src/VoxelSystem.cpp (1 of 80 files). Show all

Unified · Split

interface/src/VoxelSystem.cpp+151−38
@@ -57,13 +57,16 @@ GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 }; · 56 unmodified lines
57 57
58VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)58VoxelSystem::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 _inOcclusions(false),63 _writeArraysLock(QReadWriteLock::Recursive),
64 _showCulledSharedFaces(false),64 _readArraysLock(QReadWriteLock::Recursive),
65 _usePrimitiveRenderer(false),65 _inOcclusions(false),
66 _renderer(0) {66 _showCulledSharedFaces(false),
67 _usePrimitiveRenderer(false),
68 _renderer(0)
69{
67 70
68 _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;71 _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;
69 _writeRenderFullVBO = true;72 _writeRenderFullVBO = true;
@@ -103,6 +106,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) · 33 unmodified lines
103 106
104 _culledOnce = false;107 _culledOnce = false;
105 _inhideOutOfView = false;108 _inhideOutOfView = false;
109
110 _lastKnownVoxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
111 _lastKnownBoundaryLevelAdjust = 0;
106}112}
107 113
108void VoxelSystem::elementDeleted(OctreeElement* element) {114void VoxelSystem::elementDeleted(OctreeElement* element) {
@@ -125,6 +131,7 @@ void VoxelSystem::setDisableFastVoxelPipeline(bool disableFastVoxelPipeline) { · 16 unmodified lines
125 131
126void VoxelSystem::elementUpdated(OctreeElement* element) {132void VoxelSystem::elementUpdated(OctreeElement* element) {
127 VoxelTreeElement* voxel = (VoxelTreeElement*)element;133 VoxelTreeElement* voxel = (VoxelTreeElement*)element;
134
128 // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail..135 // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail..
129 if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) {136 if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) {
130 return;137 return;
@@ -253,6 +260,9 @@ VoxelSystem::~VoxelSystem() { · 122 unmodified lines
253 delete _tree;260 delete _tree;
254}261}
255 262
263
264// This is called by the main application thread on both the initialization of the application and when
265// the preferences dialog box is called/saved
256void VoxelSystem::setMaxVoxels(int maxVoxels) {266void VoxelSystem::setMaxVoxels(int maxVoxels) {
257 if (maxVoxels == _maxVoxels) {267 if (maxVoxels == _maxVoxels) {
258 return;268 return;
@@ -271,6 +281,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { · 12 unmodified lines
271 }281 }
272}282}
273 283
284// This is called by the main application thread on both the initialization of the application and when
285// the use voxel shader menu item is chosen
274void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {286void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
275 if (_useVoxelShader == useVoxelShader) {287 if (_useVoxelShader == useVoxelShader) {
276 return;288 return;
@@ -335,7 +347,7 @@ void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { · 58 unmodified lines
335 347
336void VoxelSystem::cleanupVoxelMemory() {348void VoxelSystem::cleanupVoxelMemory() {
337 if (_initialized) {349 if (_initialized) {
338 _bufferWriteLock.lock();350 _readArraysLock.lockForWrite();
339 _initialized = false; // no longer initialized351 _initialized = false; // no longer initialized
340 if (_useVoxelShader) {352 if (_useVoxelShader) {
341 // these are used when in VoxelShader mode.353 // these are used when in VoxelShader mode.
@@ -376,7 +388,7 @@ void VoxelSystem::cleanupVoxelMemory() { · 34 unmodified lines
376 delete[] _writeVoxelDirtyArray;388 delete[] _writeVoxelDirtyArray;
377 delete[] _readVoxelDirtyArray;389 delete[] _readVoxelDirtyArray;
378 _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL;390 _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL;
379 _bufferWriteLock.unlock();391 _readArraysLock.unlock();
380 }392 }
381}393}
382 394
@@ -409,7 +421,8 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice · 26 unmodified lines
409}421}
410 422
411void VoxelSystem::initVoxelMemory() {423void VoxelSystem::initVoxelMemory() {
412 _bufferWriteLock.lock();424 _readArraysLock.lockForWrite();
425 _writeArraysLock.lockForWrite();
413 426
414 _memoryUsageRAM = 0;427 _memoryUsageRAM = 0;
415 _memoryUsageVBO = 0; // our VBO allocations as we know them428 _memoryUsageVBO = 0; // our VBO allocations as we know them
@@ -524,7 +537,8 @@ void VoxelSystem::initVoxelMemory() { · 108 unmodified lines
524 537
525 _initialized = true;538 _initialized = true;
526 539
527 _bufferWriteLock.unlock();540 _writeArraysLock.unlock();
541 _readArraysLock.unlock();
528}542}
529 543
530void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const {544void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const {
@@ -654,7 +668,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 123 unmodified lines
654 }668 }
655 669
656 _inSetupNewVoxelsForDrawing = true;670 _inSetupNewVoxelsForDrawing = true;
657 671
658 bool didWriteFullVBO = _writeRenderFullVBO;672 bool didWriteFullVBO = _writeRenderFullVBO;
659 if (_tree->isDirty()) {673 if (_tree->isDirty()) {
660 static char buffer[64] = { 0 };674 static char buffer[64] = { 0 };
@@ -688,10 +702,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 27 unmodified lines
688 if (_voxelsUpdated) {702 if (_voxelsUpdated) {
689 _voxelsDirty=true;703 _voxelsDirty=true;
690 }704 }
691 }705 } else {
692 else {
693 // lock on the buffer write lock so we can't modify the data when the GPU is reading it706 // lock on the buffer write lock so we can't modify the data when the GPU is reading it
694 _bufferWriteLock.lock();707 _readArraysLock.lockForWrite();
695 708
696 if (_voxelsUpdated) {709 if (_voxelsUpdated) {
697 _voxelsDirty=true;710 _voxelsDirty=true;
@@ -699,8 +712,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 1 unmodified line
699 712
700 // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated713 // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated
701 copyWrittenDataToReadArrays(didWriteFullVBO);714 copyWrittenDataToReadArrays(didWriteFullVBO);
715 _readArraysLock.unlock();
702 716
703 _bufferWriteLock.unlock();
704 }717 }
705 718
706 quint64 end = usecTimestampNow();719 quint64 end = usecTimestampNow();
@@ -732,13 +745,12 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 25 unmodified lines
732 if (_usePrimitiveRenderer) {745 if (_usePrimitiveRenderer) {
733 _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty746 _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
734 _voxelsUpdated = 0;747 _voxelsUpdated = 0;
735 }748 } else {
736 else {
737 // lock on the buffer write lock so we can't modify the data when the GPU is reading it749 // lock on the buffer write lock so we can't modify the data when the GPU is reading it
738 {750 {
739 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),751 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
740 "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" );752 "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" );
741 _bufferWriteLock.lock();753 _readArraysLock.lockForWrite();
742 }754 }
743 755
744 _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty756 _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
@@ -748,8 +760,7 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 3 unmodified lines
748 760
749 // after...761 // after...
750 _voxelsUpdated = 0;762 _voxelsUpdated = 0;
751 763 _readArraysLock.unlock();
752 _bufferWriteLock.unlock();
753 }764 }
754 quint64 end = usecTimestampNow();765 quint64 end = usecTimestampNow();
755 int elapsedmsec = (end - start) / 1000;766 int elapsedmsec = (end - start) / 1000;
@@ -757,8 +768,73 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 1 unmodified line
757 _setupNewVoxelsForDrawingLastElapsed = elapsedmsec;768 _setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
758}769}
759 770
760void VoxelSystem::checkForCulling() {
761 771
772
773class recreateVoxelGeometryInViewArgs {
774public:
775 VoxelSystem* thisVoxelSystem;
776 ViewFrustum thisViewFrustum;
777 unsigned long nodesScanned;
778 float voxelSizeScale;
779 int boundaryLevelAdjust;
780
781 recreateVoxelGeometryInViewArgs(VoxelSystem* voxelSystem) :
782 thisVoxelSystem(voxelSystem),
783 thisViewFrustum(*voxelSystem->getViewFrustum()),
784 nodesScanned(0),
785 voxelSizeScale(Menu::getInstance()->getVoxelSizeScale()),
786 boundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust())
787 {
788 }
789};
790
791// The goal of this operation is to remove any old references to old geometry, and if the voxel
792// should be visible, create new geometry for it.
793bool VoxelSystem::recreateVoxelGeometryInViewOperation(OctreeElement* element, void* extraData) {
794 VoxelTreeElement* voxel = (VoxelTreeElement*)element;
795 recreateVoxelGeometryInViewArgs* args = (recreateVoxelGeometryInViewArgs*)extraData;
796
797 args->nodesScanned++;
798
799 // reset the old geometry...
800 // note: this doesn't "mark the voxel as changed", so it only releases the old buffer index thereby forgetting the
801 // old geometry
802 voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
803
804 bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, args->voxelSizeScale, args->boundaryLevelAdjust);
805 bool inView = voxel->isInView(args->thisViewFrustum);
806 voxel->setShouldRender(inView && shouldRender);
807 if (shouldRender && inView) {
808 // recreate the geometry
809 args->thisVoxelSystem->updateNodeInArrays(voxel, false, true); // DONT_REUSE_INDEX, FORCE_REDRAW
810 }
811
812 return true; // keep recursing!
813}
814
815
816// TODO: does cleanupRemovedVoxels() ever get called?
817// TODO: other than cleanupRemovedVoxels() is there anyplace we attempt to detect too many abandoned slots???
818void VoxelSystem::recreateVoxelGeometryInView() {
819
820 qDebug() << "recreateVoxelGeometryInView()...";
821
822 recreateVoxelGeometryInViewArgs args(this);
823 _writeArraysLock.lockForWrite(); // don't let anyone read or write our write arrays until we're done
824 _tree->lockForRead(); // don't let anyone change our tree structure until we're run
825
826 // reset our write arrays bookkeeping to think we've got no voxels in it
827 clearFreeBufferIndexes();
828
829 // do we need to reset out _writeVoxelDirtyArray arrays??
830 memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));
831
832 _tree->recurseTreeWithOperation(recreateVoxelGeometryInViewOperation,(void*)&args);
833 _tree->unlock();
834 _writeArraysLock.unlock();
835}
836
837void VoxelSystem::checkForCulling() {
762 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");838 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");
763 quint64 start = usecTimestampNow();839 quint64 start = usecTimestampNow();
764 840
@@ -786,7 +862,20 @@ void VoxelSystem::checkForCulling() { · 21 unmodified lines
786 _hasRecentlyChanged = false;862 _hasRecentlyChanged = false;
787 }863 }
788 864
789 hideOutOfView(forceFullFrustum);865 // This would be a good place to do a special processing pass, for example, switching the LOD of the scene
866 bool fullRedraw = (_lastKnownVoxelSizeScale != Menu::getInstance()->getVoxelSizeScale() ||
867 _lastKnownBoundaryLevelAdjust != Menu::getInstance()->getBoundaryLevelAdjust());
868
869 // track that these values
870 _lastKnownVoxelSizeScale = Menu::getInstance()->getVoxelSizeScale();
871 _lastKnownBoundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust();
872
873 if (fullRedraw) {
874 // this will remove all old geometry and recreate the correct geometry for all in view voxels
875 recreateVoxelGeometryInView();
876 } else {
877 hideOutOfView(forceFullFrustum);
878 }
790 879
791 if (forceFullFrustum) {880 if (forceFullFrustum) {
792 quint64 endViewCulling = usecTimestampNow();881 quint64 endViewCulling = usecTimestampNow();
@@ -905,12 +994,26 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { · 112 unmodified lines
905 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),994 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
906 "copyWrittenDataToReadArrays()");995 "copyWrittenDataToReadArrays()");
907 996
908 if (_voxelsDirty && _voxelsUpdated) {997 // attempt to get the writeArraysLock for reading and the readArraysLock for writing
909 if (fullVBOs) {998 // so we can copy from the write to the read... if we fail, that's ok, we'll get it the next
910 copyWrittenDataToReadArraysFullVBOs();999 // time around, the only side effect is the VBOs won't be updated this frame
1000 const int WAIT_FOR_LOCK_IN_MS = 5;
1001 if (_readArraysLock.tryLockForWrite(WAIT_FOR_LOCK_IN_MS)) {
1002 if (_writeArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) {
1003 if (_voxelsDirty && _voxelsUpdated) {
1004 if (fullVBOs) {
1005 copyWrittenDataToReadArraysFullVBOs();
1006 } else {
1007 copyWrittenDataToReadArraysPartialVBOs();
1008 }
1009 }
1010 _writeArraysLock.unlock();
911 } else {1011 } else {
912 copyWrittenDataToReadArraysPartialVBOs();1012 qDebug() << "couldn't get _writeArraysLock.LockForRead()...";
913 }1013 }
1014 _readArraysLock.unlock();
1015 } else {
1016 qDebug() << "couldn't get _readArraysLock.LockForWrite()...";
914 }1017 }
915}1018}
916 1019
@@ -1204,18 +1307,28 @@ void VoxelSystem::updateVBOs() { · 287 unmodified lines
1204 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer);1307 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer);
1205 if (! _usePrimitiveRenderer) {1308 if (! _usePrimitiveRenderer) {
1206 if (_voxelsDirty) {1309 if (_voxelsDirty) {
1207 if (_readRenderFullVBO) {1310
1208 updateFullVBOs();1311 // attempt to lock the read arrays, to for copying from them to the actual GPU VBOs.
1312 // if we fail to get the lock, that's ok, our VBOs will update on the next frame...
1313 const int WAIT_FOR_LOCK_IN_MS = 5;
1314 if (_readArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) {
1315 if (_readRenderFullVBO) {
1316 updateFullVBOs();
1317 } else {
1318 updatePartialVBOs();
1319 }
1320 _voxelsDirty = false;
1321 _readRenderFullVBO = false;
1322 _readArraysLock.unlock();
1209 } else {1323 } else {
1210 updatePartialVBOs();1324 qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()";
1211 }1325 }
1212 _voxelsDirty = false;
1213 _readRenderFullVBO = false;
1214 }1326 }
1215 }1327 }
1216 _callsToTreesToArrays = 0; // clear it1328 _callsToTreesToArrays = 0; // clear it
1217}1329}
1218 1330
1331// this should only be called on the main application thread during render
1219void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {1332void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
1220 bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);1333 bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
1221 PerformanceWarning warn(showWarning, "updateVBOSegment()");1334 PerformanceWarning warn(showWarning, "updateVBOSegment()");
@@ -1261,7 +1374,8 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg · 39 unmodified lines
1261 }1374 }
1262}1375}
1263 1376
1264void VoxelSystem::render(bool texture) {1377void VoxelSystem::render() {
1378 bool texture = Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures);
1265 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);1379 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
1266 PerformanceWarning warn(showWarnings, "render()");1380 PerformanceWarning warn(showWarnings, "render()");
1267 1381
@@ -1478,11 +1592,7 @@ void VoxelSystem::killLocalVoxels() { · 210 unmodified lines
1478 setupNewVoxelsForDrawing();1592 setupNewVoxelsForDrawing();
1479}1593}
1480 1594
1481void VoxelSystem::redrawInViewVoxels() {1595// only called on main thread
1482 hideOutOfView(true);
1483}
1484
1485
1486bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData) {1596bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData) {
1487 _nodeCount++;1597 _nodeCount++;
1488 VoxelTreeElement* voxel = (VoxelTreeElement*)element;1598 VoxelTreeElement* voxel = (VoxelTreeElement*)element;
@@ -1491,12 +1601,15 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void · 2 unmodified lines
1491 return true;1601 return true;
1492}1602}
1493 1603
1604// only called on main thread, and also always followed by a call to cleanupVoxelMemory()
1605// you shouldn't be calling this on any other thread or without also cleaning up voxel memory
1494void VoxelSystem::clearAllNodesBufferIndex() {1606void VoxelSystem::clearAllNodesBufferIndex() {
1495 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), 1607 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
1496 "VoxelSystem::clearAllNodesBufferIndex()");1608 "VoxelSystem::clearAllNodesBufferIndex()");
1497 _nodeCount = 0;1609 _nodeCount = 0;
1498 _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read1610 _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read
1499 _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);1611 _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
1612 clearFreeBufferIndexes(); // this should be called too
1500 _tree->unlock();1613 _tree->unlock();
1501 if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {1614 if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
1502 qDebug("clearing buffer index of %d nodes", _nodeCount);1615 qDebug("clearing buffer index of %d nodes", _nodeCount);