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
5757
5858 VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
5959 : NodeData(),
60− _treeScale(treeScale),
61− _maxVoxels(maxVoxels),
62− _initialized(false),
63− _inOcclusions(false),
64− _showCulledSharedFaces(false),
65− _usePrimitiveRenderer(false),
66− _renderer(0) {
60+ _treeScale(treeScale),
61+ _maxVoxels(maxVoxels),
62+ _initialized(false),
63+ _writeArraysLock(QReadWriteLock::Recursive),
64+ _readArraysLock(QReadWriteLock::Recursive),
65+ _inOcclusions(false),
66+ _showCulledSharedFaces(false),
67+ _usePrimitiveRenderer(false),
68+ _renderer(0)
69+{
6770
6871 _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;
6972 _writeRenderFullVBO = true;
@@ -103,6 +106,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) · 33 unmodified lines
103106
104107 _culledOnce = false;
105108 _inhideOutOfView = false;
109+
110+ _lastKnownVoxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
111+ _lastKnownBoundaryLevelAdjust = 0;
106112 }
107113
108114 void VoxelSystem::elementDeleted(OctreeElement* element) {
@@ -125,6 +131,7 @@ void VoxelSystem::setDisableFastVoxelPipeline(bool disableFastVoxelPipeline) { · 16 unmodified lines
125131
126132 void VoxelSystem::elementUpdated(OctreeElement* element) {
127133 VoxelTreeElement* voxel = (VoxelTreeElement*)element;
134+
128135 // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail..
129136 if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) {
130137 return;
@@ -253,6 +260,9 @@ VoxelSystem::~VoxelSystem() { · 122 unmodified lines
253260 delete _tree;
254261 }
255262
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
256266 void VoxelSystem::setMaxVoxels(int maxVoxels) {
257267 if (maxVoxels == _maxVoxels) {
258268 return;
@@ -271,6 +281,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { · 12 unmodified lines
271281 }
272282 }
273283
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
274286 void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
275287 if (_useVoxelShader == useVoxelShader) {
276288 return;
@@ -335,7 +347,7 @@ void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { · 58 unmodified lines
335347
336348 void VoxelSystem::cleanupVoxelMemory() {
337349 if (_initialized) {
338− _bufferWriteLock.lock();
350+ _readArraysLock.lockForWrite();
339351 _initialized = false; // no longer initialized
340352 if (_useVoxelShader) {
341353 // these are used when in VoxelShader mode.
@@ -376,7 +388,7 @@ void VoxelSystem::cleanupVoxelMemory() { · 34 unmodified lines
376388 delete[] _writeVoxelDirtyArray;
377389 delete[] _readVoxelDirtyArray;
378390 _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL;
379− _bufferWriteLock.unlock();
391+ _readArraysLock.unlock();
380392 }
381393 }
382394
@@ -409,7 +421,8 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice · 26 unmodified lines
409421 }
410422
411423 void VoxelSystem::initVoxelMemory() {
412− _bufferWriteLock.lock();
424+ _readArraysLock.lockForWrite();
425+ _writeArraysLock.lockForWrite();
413426
414427 _memoryUsageRAM = 0;
415428 _memoryUsageVBO = 0; // our VBO allocations as we know them
@@ -524,7 +537,8 @@ void VoxelSystem::initVoxelMemory() { · 108 unmodified lines
524537
525538 _initialized = true;
526539
527− _bufferWriteLock.unlock();
540+ _writeArraysLock.unlock();
541+ _readArraysLock.unlock();
528542 }
529543
530544 void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const {
@@ -654,7 +668,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 123 unmodified lines
654668 }
655669
656670 _inSetupNewVoxelsForDrawing = true;
657−
671+
658672 bool didWriteFullVBO = _writeRenderFullVBO;
659673 if (_tree->isDirty()) {
660674 static char buffer[64] = { 0 };
@@ -688,10 +702,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 27 unmodified lines
688702 if (_voxelsUpdated) {
689703 _voxelsDirty=true;
690704 }
691− }
692− else {
705+ } else {
693706 // 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();
695708
696709 if (_voxelsUpdated) {
697710 _voxelsDirty=true;
@@ -699,8 +712,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 1 unmodified line
699712
700713 // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated
701714 copyWrittenDataToReadArrays(didWriteFullVBO);
715+ _readArraysLock.unlock();
702716
703− _bufferWriteLock.unlock();
704717 }
705718
706719 quint64 end = usecTimestampNow();
@@ -732,13 +745,12 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 25 unmodified lines
732745 if (_usePrimitiveRenderer) {
733746 _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
734747 _voxelsUpdated = 0;
735− }
736− else {
748+ } else {
737749 // lock on the buffer write lock so we can't modify the data when the GPU is reading it
738750 {
739751 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
740752 "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" );
741− _bufferWriteLock.lock();
753+ _readArraysLock.lockForWrite();
742754 }
743755
744756 _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
748760
749761 // after...
750762 _voxelsUpdated = 0;
751−
752− _bufferWriteLock.unlock();
763+ _readArraysLock.unlock();
753764 }
754765 quint64 end = usecTimestampNow();
755766 int elapsedmsec = (end - start) / 1000;
@@ -757,8 +768,73 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 1 unmodified line
757768 _setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
758769 }
759770
760−void VoxelSystem::checkForCulling() {
761771
772+
773+class recreateVoxelGeometryInViewArgs {
774+public:
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.
793+bool 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???
818+void 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+
837+void VoxelSystem::checkForCulling() {
762838 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");
763839 quint64 start = usecTimestampNow();
764840
@@ -786,7 +862,20 @@ void VoxelSystem::checkForCulling() { · 21 unmodified lines
786862 _hasRecentlyChanged = false;
787863 }
788864
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+ }
790879
791880 if (forceFullFrustum) {
792881 quint64 endViewCulling = usecTimestampNow();
@@ -905,12 +994,26 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { · 112 unmodified lines
905994 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
906995 "copyWrittenDataToReadArrays()");
907996
908− if (_voxelsDirty && _voxelsUpdated) {
909− if (fullVBOs) {
910− copyWrittenDataToReadArraysFullVBOs();
997+ // attempt to get the writeArraysLock for reading and the readArraysLock for writing
998+ // so we can copy from the write to the read... if we fail, that's ok, we'll get it the next
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();
9111011 } else {
912− copyWrittenDataToReadArraysPartialVBOs();
1012+ qDebug() << "couldn't get _writeArraysLock.LockForRead()...";
9131013 }
1014+ _readArraysLock.unlock();
1015+ } else {
1016+ qDebug() << "couldn't get _readArraysLock.LockForWrite()...";
9141017 }
9151018 }
9161019
@@ -1204,18 +1307,28 @@ void VoxelSystem::updateVBOs() { · 287 unmodified lines
12041307 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer);
12051308 if (! _usePrimitiveRenderer) {
12061309 if (_voxelsDirty) {
1207− if (_readRenderFullVBO) {
1208− updateFullVBOs();
1310+
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();
12091323 } else {
1210− updatePartialVBOs();
1324+ qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()";
12111325 }
1212− _voxelsDirty = false;
1213− _readRenderFullVBO = false;
12141326 }
12151327 }
12161328 _callsToTreesToArrays = 0; // clear it
12171329 }
12181330
1331+// this should only be called on the main application thread during render
12191332 void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
12201333 bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
12211334 PerformanceWarning warn(showWarning, "updateVBOSegment()");
@@ -1261,7 +1374,8 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg · 39 unmodified lines
12611374 }
12621375 }
12631376
1264−void VoxelSystem::render(bool texture) {
1377+void VoxelSystem::render() {
1378+ bool texture = Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures);
12651379 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
12661380 PerformanceWarning warn(showWarnings, "render()");
12671381
@@ -1478,11 +1592,7 @@ void VoxelSystem::killLocalVoxels() { · 210 unmodified lines
14781592 setupNewVoxelsForDrawing();
14791593 }
14801594
1481−void VoxelSystem::redrawInViewVoxels() {
1482− hideOutOfView(true);
1483−}
1484−
1485−
1595+// only called on main thread
14861596 bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData) {
14871597 _nodeCount++;
14881598 VoxelTreeElement* voxel = (VoxelTreeElement*)element;
@@ -1491,12 +1601,15 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void · 2 unmodified lines
14911601 return true;
14921602 }
14931603
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
14941606 void VoxelSystem::clearAllNodesBufferIndex() {
14951607 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
14961608 "VoxelSystem::clearAllNodesBufferIndex()");
14971609 _nodeCount = 0;
14981610 _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read
14991611 _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
1612+ clearFreeBufferIndexes(); // this should be called too
15001613 _tree->unlock();
15011614 if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
15021615 qDebug("clearing buffer index of %d nodes", _nodeCount);