From 754690e2513380580f98b770a654f45ed87858ee Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 5 Feb 2011 17:56:59 +0000 Subject: [PATCH] Removed block sharing ready for compression. --- examples/Basic/main.cpp | 2 +- examples/OpenGL/main.cpp | 4 - .../PolyVoxCore/include/PolyVoxImpl/Block.h | 4 +- .../PolyVoxCore/include/PolyVoxImpl/Block.inl | 47 ++++--- library/PolyVoxCore/include/Volume.h | 17 +-- library/PolyVoxCore/include/Volume.inl | 129 ++---------------- library/PolyVoxCore/include/VolumeSampler.inl | 6 +- tests/testvolume.cpp | 2 - 8 files changed, 41 insertions(+), 170 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index b140f432..2318d55c 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -421,7 +421,7 @@ int main(int argc, char *argv[]) openGLWidget.show(); //Create an empty volume and then place a sphere in it - Volume volData(256, 256, 256); + Volume volData(128, 128, 128); //createSphereInVolume(volData, 30); createPerlinVolume(volData); diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 99c1f4f1..daf587f0 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -104,10 +104,6 @@ int main(int argc, char *argv[]) smoothRegion(volData, PolyVox::Region(Vector3DInt16(62, 62, 62), Vector3DInt16(130, 130, 130))); smoothRegion(volData, PolyVox::Region(Vector3DInt16(62, 62, 62), Vector3DInt16(130, 130, 130))); - cout << "Tidying memory..."; - volData.tidyUpMemory(0); - cout << "done." << endl; - QApplication app(argc, argv); OpenGLWidget openGLWidget(0); diff --git a/library/PolyVoxCore/include/PolyVoxImpl/Block.h b/library/PolyVoxCore/include/PolyVoxImpl/Block.h index e95c1923..9d23e2cd 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxImpl/Block.h @@ -34,7 +34,7 @@ namespace PolyVox //Make VolumeSampler a friend friend class VolumeSampler; public: - Block(uint16_t uSideLength); + Block(uint16_t uSideLength = 0); Block(const Block& rhs); ~Block(); @@ -48,7 +48,7 @@ namespace PolyVox void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); void fill(VoxelType tValue); - bool isHomogeneous(void); + void resize(uint16_t uSideLength); uint32_t sizeInChars(void); private: diff --git a/library/PolyVoxCore/include/PolyVoxImpl/Block.inl b/library/PolyVoxCore/include/PolyVoxImpl/Block.inl index c088917f..0143ed92 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxImpl/Block.inl @@ -33,24 +33,14 @@ namespace PolyVox { template Block::Block(uint16_t uSideLength) - :m_tData(0) + :m_uSideLength(0) + ,m_uSideLengthPower(0) + ,m_tData(0) { - //Debug mode validation - assert(isPowerOf2(uSideLength)); - - //Release mode validation - if(!isPowerOf2(uSideLength)) + if(uSideLength != 0) { - throw std::invalid_argument("Block side length must be a power of two."); + resize(uSideLength); } - - //Compute the side length - m_uSideLength = uSideLength; - m_uSideLengthPower = logBase2(uSideLength); - - //If this fails an exception will be thrown. Memory is not - //allocated and there is nothing else in this class to clean up - m_tData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; } template @@ -146,19 +136,28 @@ namespace PolyVox } template - bool Block::isHomogeneous(void) + void Block::resize(uint16_t uSideLength) { - const VoxelType tFirstVoxel = m_tData[0]; - const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; + //Debug mode validation + assert(isPowerOf2(uSideLength)); - for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct) + //Release mode validation + if(!isPowerOf2(uSideLength)) { - if(m_tData[ct] != tFirstVoxel) - { - return false; - } + throw std::invalid_argument("Block side length must be a power of two."); } - return true; + + //Compute the side length + m_uSideLength = uSideLength; + m_uSideLengthPower = logBase2(uSideLength); + + //Delete the old data + delete[] m_tData; + m_tData = 0; + + //If this fails an exception will be thrown. Memory is not + //allocated and there is nothing else in this class to clean up + m_tData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; } template diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index 72e10789..32d7f672 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -153,21 +153,10 @@ namespace PolyVox ///Resises the volume to the specified dimensions void resize(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength = 32); - void tidyUpMemory(uint32_t uNoOfBlocksToProcess = 1000000); private: - polyvox_shared_ptr< Block > getHomogenousBlock(VoxelType tHomogenousValue); - - polyvox_shared_ptr< Block > m_pBorderBlock; - std::vector< polyvox_shared_ptr< Block > > m_pBlocks; - std::vector m_vecBlockIsPotentiallyHomogenous; - - //Note: We were once storing weak_ptr's in this map, so that the blocks would be deleted once they - //were not being referenced by anyone else. However, this made it difficult to know when a block was - //shared. A call to shared_ptr::unique() from within setVoxel was not sufficient as weak_ptr's did - //not contribute to the reference count. Instead we store shared_ptr's here, and check if they - //are used by anyone else (i.e are non-unique) when we tidy the volume. - std::map > > m_pHomogenousBlock; + Block m_pBorderBlock; + std::vector< Block > m_pBlocks; uint32_t m_uNoOfBlocksInVolume; @@ -185,8 +174,6 @@ namespace PolyVox uint16_t m_uLongestSideLength; uint16_t m_uShortestSideLength; float m_fDiagonalLength; - - uint32_t m_uCurrentBlockForTidying; }; //Some handy typedefs diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index 7a0aea34..d1fd9a4c 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -53,9 +53,7 @@ namespace PolyVox resize(uWidth, uHeight, uDepth, uBlockSideLength); //Create the border block - polyvox_shared_ptr< Block > pTempBlock(new Block(m_uBlockSideLength)); - pTempBlock->fill(VoxelType()); - m_pBorderBlock = pTempBlock; + m_pBorderBlock.fill(VoxelType()); } //////////////////////////////////////////////////////////////////////////////// @@ -74,7 +72,7 @@ namespace PolyVox template VoxelType Volume::getBorderValue(void) const { - return m_pBorderBlock->getVoxelAt(0,0,0); + return m_pBorderBlock.getVoxelAt(0,0,0); } //////////////////////////////////////////////////////////////////////////////// @@ -174,14 +172,14 @@ namespace PolyVox const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); - const polyvox_shared_ptr< Block< VoxelType > >& block = m_pBlocks + const Block& block = m_pBlocks [ blockX + blockY * m_uWidthInBlocks + blockZ * m_uWidthInBlocks * m_uHeightInBlocks ]; - return block->getVoxelAt(xOffset,yOffset,zOffset); + return block.getVoxelAt(xOffset,yOffset,zOffset); } else { @@ -205,7 +203,7 @@ namespace PolyVox template void Volume::setBorderValue(const VoxelType& tBorder) { - return m_pBorderBlock->fill(tBorder); + return m_pBorderBlock.fill(tBorder); } //////////////////////////////////////////////////////////////////////////////// @@ -235,28 +233,10 @@ namespace PolyVox blockY * m_uWidthInBlocks + blockZ * m_uWidthInBlocks * m_uHeightInBlocks; - polyvox_shared_ptr< Block >& block = m_pBlocks[uBlockIndex]; + Block& block = m_pBlocks[uBlockIndex]; + + block.setVoxelAt(xOffset,yOffset,zOffset, tValue); - //It's quite possible that the user might attempt to set a voxel to it's current value. - //We test for this case firstly because it could help performance, but more importantly - //because it lets us avoid unsharing blocks unnecessarily. - if(block->getVoxelAt(xOffset, yOffset, zOffset) != tValue) - { - if(block.unique()) - { - block->setVoxelAt(xOffset,yOffset,zOffset, tValue); - //There is a chance that setting this voxel makes the block homogenous and therefore shareable. - //But checking this will take some time, so for now just set a flag. - m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = true; - } - else - { - polyvox_shared_ptr< Block > pNewBlock(new Block(*(block))); - block = pNewBlock; - m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = false; - block->setVoxelAt(xOffset,yOffset,zOffset, tValue); - } - } //Return true to indicate that we modified a voxel. return true; } @@ -324,8 +304,6 @@ namespace PolyVox //Clear the previous data m_pBlocks.clear(); - m_vecBlockIsPotentiallyHomogenous.clear(); - m_pHomogenousBlock.clear(); //Compute the volume side lengths m_uWidth = uWidth; @@ -346,101 +324,14 @@ namespace PolyVox //Create the blocks m_pBlocks.resize(m_uNoOfBlocksInVolume); - m_vecBlockIsPotentiallyHomogenous.resize(m_uNoOfBlocksInVolume); for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) { - m_pBlocks[i] = getHomogenousBlock(VoxelType()); - m_vecBlockIsPotentiallyHomogenous[i] = false; - } + m_pBlocks[i].resize(m_uBlockSideLength); + } //Other properties we might find useful later m_uLongestSideLength = (std::max)((std::max)(m_uWidth,m_uHeight),m_uDepth); m_uShortestSideLength = (std::min)((std::min)(m_uWidth,m_uHeight),m_uDepth); m_fDiagonalLength = sqrtf(static_cast(m_uWidth * m_uWidth + m_uHeight * m_uHeight + m_uDepth * m_uDepth)); - - //Reset the counter for tidying - m_uCurrentBlockForTidying = 0; - } - - //////////////////////////////////////////////////////////////////////////////// - /// Clean up the memory usage of the volume. Checks for any blocks which are - /// homogeneous and flags them as such for faster processing and reduced memory - /// usage. - /// \param uNoOfBlocksToProcess the number of blocks to process - //////////////////////////////////////////////////////////////////////////////// - template - void Volume::tidyUpMemory(uint32_t uNoOfBlocksToProcess) - { - //Track the number of blocks we have processed. - uint32_t m_uNoOfProcessedBlocks = 0; - - //We will loop around, and finish if we get back to our start position - uint32_t uFinishBlock = m_uCurrentBlockForTidying; - - //Increment the current block, looping around if necessary - ++m_uCurrentBlockForTidying; - m_uCurrentBlockForTidying %= m_uNoOfBlocksInVolume; - - //While we have not reached the user specified limit and there are more blocks to process... - while((m_uNoOfProcessedBlocks < uNoOfBlocksToProcess) && (m_uCurrentBlockForTidying != uFinishBlock)) - { - //We only do any work if the block is flagged as potentially homogeneous. - if(m_vecBlockIsPotentiallyHomogenous[m_uCurrentBlockForTidying]) - { - //Check if it's really homogeneous (this can be slow). - if(m_pBlocks[m_uCurrentBlockForTidying]->isHomogeneous()) - { - //If so, replace is with a block from out homogeneous collection. - VoxelType homogeneousValue = m_pBlocks[m_uCurrentBlockForTidying]->getVoxelAt(0,0,0); - m_pBlocks[m_uCurrentBlockForTidying] = getHomogenousBlock(homogeneousValue); - } - - //Either way, we have now determined whether the block was sharable. So it's not *potentially* sharable. - m_vecBlockIsPotentiallyHomogenous[m_uCurrentBlockForTidying] = false; - - //We've processed a block. This is inside the 'if' because the path outside the 'if' is trivially fast. - ++m_uNoOfProcessedBlocks; - } - - //Increment the current block, looping around if necessary - ++m_uCurrentBlockForTidying; - m_uCurrentBlockForTidying %= m_uNoOfBlocksInVolume; - } - - //Identify and remove any homogeneous blocks which are not actually in use. - typename std::map > >::iterator iter = m_pHomogenousBlock.begin(); - while(iter != m_pHomogenousBlock.end()) - { - if(iter->second.unique()) - { - m_pHomogenousBlock.erase(iter++); //Increments the iterator and returns the previous position to be erased. - } - else - { - ++iter; //Just increments the iterator. - } - } - } - - template - polyvox_shared_ptr< Block > Volume::getHomogenousBlock(VoxelType tHomogenousValue) - { - typename std::map > >::iterator iterResult = m_pHomogenousBlock.find(tHomogenousValue); - if(iterResult == m_pHomogenousBlock.end()) - { - //Block block; - polyvox_shared_ptr< Block > pHomogeneousBlock(new Block(m_uBlockSideLength)); - //block.m_pBlock = temp; - //block.m_uReferenceCount++; - pHomogeneousBlock->fill(tHomogenousValue); - m_pHomogenousBlock.insert(std::make_pair(tHomogenousValue, pHomogeneousBlock)); - return pHomogeneousBlock; - } - else - { - //iterResult->second.m_uReferenceCount++; - //polyvox_shared_ptr< Block > result(iterResult->second); - return iterResult->second; - } } } diff --git a/library/PolyVoxCore/include/VolumeSampler.inl b/library/PolyVoxCore/include/VolumeSampler.inl index dc15f8a5..a9752074 100644 --- a/library/PolyVoxCore/include/VolumeSampler.inl +++ b/library/PolyVoxCore/include/VolumeSampler.inl @@ -153,13 +153,13 @@ namespace PolyVox const uint32_t uBlockIndexInVolume = uXBlock + uYBlock * mVolume->m_uWidthInBlocks + uZBlock * mVolume->m_uWidthInBlocks * mVolume->m_uHeightInBlocks; - const polyvox_shared_ptr< Block >& currentBlock = mVolume->m_pBlocks[uBlockIndexInVolume]; + const Block& currentBlock = mVolume->m_pBlocks[uBlockIndexInVolume]; - mCurrentVoxel = currentBlock->m_tData + uVoxelIndexInBlock; + mCurrentVoxel = currentBlock.m_tData + uVoxelIndexInBlock; } else { - mCurrentVoxel = mVolume->m_pBorderBlock->m_tData + uVoxelIndexInBlock; + mCurrentVoxel = mVolume->m_pBorderBlock.m_tData + uVoxelIndexInBlock; } } diff --git a/tests/testvolume.cpp b/tests/testvolume.cpp index ccbd0dc4..b834fffa 100644 --- a/tests/testvolume.cpp +++ b/tests/testvolume.cpp @@ -46,8 +46,6 @@ void TestVolume::testSize() } } - volData.tidyUpMemory(0); - QCOMPARE(volData.getWidth(), g_uVolumeSideLength); QCOMPARE(volData.getHeight(), g_uVolumeSideLength); QCOMPARE(volData.getDepth(), g_uVolumeSideLength);