From 81d2bb6408ab83f04e5ed6bf17bef9c0146a58a0 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 10 Feb 2011 22:43:34 +0000 Subject: [PATCH] Refactoring and tidying. --- examples/Basic/main.cpp | 3 +- .../PolyVoxCore/include/PolyVoxImpl/Block.h | 28 +++-- .../PolyVoxCore/include/PolyVoxImpl/Block.inl | 107 +++++------------- library/PolyVoxCore/include/Volume.h | 16 ++- library/PolyVoxCore/include/Volume.inl | 65 +++++++---- 5 files changed, 104 insertions(+), 115 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index c73b8f5b..fc9284ad 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -502,9 +502,10 @@ int main(int argc, char *argv[]) openGLWidget.show(); //Create an empty volume and then place a sphere in it - Volume volData(1024, 1280, 256); + Volume volData(4096, 4096, 256); //createSphereInVolume(volData, 30); createPerlinTerrain(volData); + //createPerlinVolumeSlow(volData); volData.setBlockCacheSize(8); /*srand(12345); diff --git a/library/PolyVoxCore/include/PolyVoxImpl/Block.h b/library/PolyVoxCore/include/PolyVoxImpl/Block.h index 5432518b..bad3a813 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxImpl/Block.h @@ -33,11 +33,21 @@ namespace PolyVox template class Block { + template + struct RunlengthEntry + { + LengthType length; + VoxelType value; + + //We can parametise the length on anything up to uint32_t. + //This lets us experiment with the optimal size in the future. + static uint32_t maxRunlength(void) {return (std::numeric_limits::max)();} + }; + //Make VolumeSampler a friend friend class VolumeSampler; public: Block(uint16_t uSideLength = 0); - ~Block(); uint16_t getSideLength(void) const; VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; @@ -47,22 +57,20 @@ namespace PolyVox void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); void fill(VoxelType tValue); - void resize(uint16_t uSideLength); - uint32_t sizeInChars(void); + void initialise(uint16_t uSideLength); + uint32_t sizeInBytes(void); public: void compress(void); - void uncompress(void); + void uncompress(VoxelType* pData); + std::vector< RunlengthEntry > m_vecCompressedData; + uint64_t m_uTimestamp; + VoxelType* m_tUncompressedData; uint16_t m_uSideLength; uint8_t m_uSideLengthPower; - VoxelType* m_tUncompressedData; bool m_bIsCompressed; - bool m_bIsUncompressedDataModified; - uint64_t m_uTimestamp; - - std::vector runlengths; - std::vector values; + bool m_bIsUncompressedDataModified; private: Block(const Block& rhs); diff --git a/library/PolyVoxCore/include/PolyVoxImpl/Block.inl b/library/PolyVoxCore/include/PolyVoxImpl/Block.inl index 65844807..a9b1c27f 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxImpl/Block.inl @@ -43,7 +43,7 @@ namespace PolyVox { if(uSideLength != 0) { - resize(uSideLength); + initialise(uSideLength); } } @@ -53,13 +53,6 @@ namespace PolyVox assert(false); } - template - Block::~Block() - { - delete[] m_tUncompressedData; - m_tUncompressedData = 0; - } - template Block& Block::operator=(const Block& rhs) { @@ -124,11 +117,10 @@ namespace PolyVox template void Block::fill(VoxelType tValue) { - //The memset *may* be faster than the std::fill(), but it doesn't compile nicely - //in 64-bit mode as casting the pointer to an int causes a loss of precision. - assert(m_tUncompressedData); + //The memset *may* be faster than the std::fill(), but it doesn't compile nicely + //in 64-bit mode as casting the pointer to an int causes a loss of precision. const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue); @@ -136,7 +128,7 @@ namespace PolyVox } template - void Block::resize(uint16_t uSideLength) + void Block::initialise(uint16_t uSideLength) { //Debug mode validation assert(isPowerOf2(uSideLength)); @@ -150,120 +142,77 @@ namespace PolyVox //Compute the side length m_uSideLength = uSideLength; m_uSideLengthPower = logBase2(uSideLength); - - - if(m_bIsCompressed == false) - { - //Delete the old data - delete[] m_tUncompressedData; - m_tUncompressedData = 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_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; - - m_bIsUncompressedDataModified = true; - } } template - uint32_t Block::sizeInChars(void) + uint32_t Block::sizeInBytes(void) { - uint32_t uSizeInChars = 0; //sizeof(Block); - - if(m_tUncompressedData != 0) - { - const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; - uSizeInChars += uNoOfVoxels * sizeof(VoxelType); - } - - uSizeInChars += values.size() * sizeof(VoxelType); - uSizeInChars += runlengths.size() * sizeof(uint16_t); - - return uSizeInChars; + uint32_t uSizeInBytes = sizeof(Block); + uSizeInBytes += m_vecCompressedData.size() * sizeof(RunlengthEntry); + return uSizeInBytes; } template void Block::compress(void) { assert(m_bIsCompressed == false); + assert(m_tUncompressedData != 0); //If the uncompressed data hasn't actually been //modified then we don't need to redo the compression. if(m_bIsUncompressedDataModified) { uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; - runlengths.clear(); - values.clear(); + m_vecCompressedData.clear(); - VoxelType current = m_tUncompressedData[0]; - uint16_t runLength = 1; + RunlengthEntry entry; + entry.length = 1; + entry.value = m_tUncompressedData[0]; for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct) { VoxelType value = m_tUncompressedData[ct]; - if((value == current) && (runLength < (std::numeric_limits::max)())) + if((value == entry.value) && (entry.length < entry.maxRunlength())) { - runLength++; + entry.length++; } else { - runlengths.push_back(runLength); - values.push_back(current); - current = value; - runLength = 1; + m_vecCompressedData.push_back(entry); + entry.value = value; + entry.length = 1; } } - runlengths.push_back(runLength); - values.push_back(current); + m_vecCompressedData.push_back(entry); //Shrink the vectors to their contents (seems slow?): //http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector //C++0x may have a shrink_to_fit() function? - //std::vector(runlengths).swap(runlengths); - //std::vector(values).swap(values); + //std::vector(m_vecCompressedData).swap(m_vecCompressedData); } - assert(m_tUncompressedData != 0); - delete[] m_tUncompressedData; + //Flag the uncompressed data as no longer being used but don't delete it (we don't own it). m_tUncompressedData = 0; m_bIsCompressed = true; } template - void Block::uncompress(void) + void Block::uncompress(VoxelType* pData) { assert(m_bIsCompressed == true); assert(m_tUncompressedData == 0); - m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; + m_tUncompressedData = pData; - VoxelType* pUncompressedData = m_tUncompressedData; - - //memset should provide the fastest way of expanding the data, but it works - //on unsigned chars so is only possible if our voxel type is the right size. - //Nore that memset takes an int type, but sonverts it to unsiogned char: - //http://www.cplusplus.com/reference/clibrary/cstring/memset/ - /*if(sizeof(VoxelType) == sizeof(unsigned char)) + VoxelType* pUncompressedData = m_tUncompressedData; + for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct) { - for(uint32_t ct = 0; ct < runlengths.size(); ++ct) + for(uint32_t i = 0; i < m_vecCompressedData[ct].length; ++i) { - memset(pUncompressedData, *((int*)(&values[ct])), runlengths[ct]); - pUncompressedData += runlengths[ct]; + *pUncompressedData = m_vecCompressedData[ct].value; + ++pUncompressedData; } } - //Otherwise we fall back on a loop. - else - {*/ - for(uint32_t ct = 0; ct < runlengths.size(); ++ct) - { - for(uint32_t i = 0; i < runlengths[ct]; ++i) - { - *pUncompressedData = values[ct]; - ++pUncompressedData; - } - } - //} m_bIsCompressed = false; m_bIsUncompressedDataModified = false; diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index e66b4ec4..be01b95b 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -118,6 +118,13 @@ namespace PolyVox //Make VolumeSampler a friend friend class VolumeSampler; + struct UncompressedBlock + { + Block* block; + VoxelType* data; + + }; + public: ///Constructor Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength = 32); @@ -158,15 +165,18 @@ namespace PolyVox void setBlockCacheSize(uint16_t uBlockCacheSize); void clearBlockCache(void); - uint32_t sizeInChars(void); + uint32_t sizeInBytes(void); public: Block* getUncompressedBlock(Block* block) const; Block m_pBorderBlock; Block* m_pBlocks; - mutable std::vector*> m_pUncompressedBlocks; - uint16_t m_uBlockCacheSize; + //mutable std::vector*> m_pUncompressedBlocks; + //mutable std::vector< std::vector > m_pUncompressedBlockData; + //mutable VoxelType* m_pUncompressedBlockData; + mutable std::vector< UncompressedBlock > m_vecUncompressedBlockCache; + uint16_t m_uMaxUncompressedBlockCacheSize; uint32_t m_uNoOfBlocksInVolume; diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index 763c415b..eb45c8f4 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -49,13 +49,13 @@ namespace PolyVox template Volume::Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength) :m_uTimestamper(0) - ,m_uBlockCacheSize(256) + ,m_uMaxUncompressedBlockCacheSize(256) ,m_uCompressions(0) ,m_uUncompressions(0) ,m_uBlockSideLength(uBlockSideLength) ,m_pBlocks(0) { - setBlockCacheSize(m_uBlockCacheSize); + setBlockCacheSize(m_uMaxUncompressedBlockCacheSize); //Create a volume of the right size. resize(uWidth, uHeight, uDepth, uBlockSideLength); @@ -272,13 +272,13 @@ namespace PolyVox template void Volume::clearBlockCache(void) { - for(uint32_t ct = 0; ct < m_pUncompressedBlocks.size(); ct++) + for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) { - m_pUncompressedBlocks[ct]->compress(); + m_vecUncompressedBlockCache[ct].block->compress(); + delete[] m_vecUncompressedBlockCache[ct].data; m_uCompressions++; } - - m_pUncompressedBlocks.clear(); + m_vecUncompressedBlockCache.clear(); } //////////////////////////////////////////////////////////////////////////////// @@ -350,11 +350,11 @@ namespace PolyVox m_pBlocks = new Block[m_uNoOfBlocksInVolume]; for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) { - m_pBlocks[i].resize(m_uBlockSideLength); + m_pBlocks[i].initialise(m_uBlockSideLength); } //Create the border block - m_pBorderBlock.resize(uBlockSideLength); + m_pBorderBlock.initialise(uBlockSideLength); Block* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock); pUncompressedBorderBlock->fill(VoxelType()); @@ -369,7 +369,19 @@ namespace PolyVox { clearBlockCache(); - m_uBlockCacheSize = uBlockCacheSize; + m_uMaxUncompressedBlockCacheSize = uBlockCacheSize; + + /*m_pUncompressedBlockCache.resize(uBlockCacheSize); + for(uint32_t ct = 0; ct < m_pUncompressedBlockData.size(); ct++) + { + m_pUncompressedBlockData[ct].data + VoxelType empty; + empty.setMaterial(0); + empty.setDensity(0); + std::fill(m_pUncompressedBlockData[ct].begin(), m_pUncompressedBlockData[ct].end(), empty); + } + m_pUncompressedBlockData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * m_uBlockCacheSize]; + memset(m_pUncompressedBlockData, 0, m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * m_uBlockCacheSize);*/ } template @@ -384,43 +396,52 @@ namespace PolyVox uint32_t uUncompressedBlockIndex = 100000000; - assert(m_pUncompressedBlocks.size() <= m_uBlockCacheSize); - if(m_pUncompressedBlocks.size() == m_uBlockCacheSize) + assert(m_vecUncompressedBlockCache.size() <= m_uMaxUncompressedBlockCacheSize); + if(m_vecUncompressedBlockCache.size() == m_uMaxUncompressedBlockCacheSize) { int32_t leastRecentlyUsedBlockIndex = -1; uint64_t uLeastRecentTimestamp = 1000000000000000; - for(uint32_t ct = 0; ct < m_pUncompressedBlocks.size(); ct++) + for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) { - if(m_pUncompressedBlocks[ct]->m_uTimestamp < uLeastRecentTimestamp) + if(m_vecUncompressedBlockCache[ct].block->m_uTimestamp < uLeastRecentTimestamp) { - uLeastRecentTimestamp = m_pUncompressedBlocks[ct]->m_uTimestamp; + uLeastRecentTimestamp = m_vecUncompressedBlockCache[ct].block->m_uTimestamp; leastRecentlyUsedBlockIndex = ct; } } - m_pUncompressedBlocks[leastRecentlyUsedBlockIndex]->compress(); + uUncompressedBlockIndex = leastRecentlyUsedBlockIndex; + m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block->compress(); + m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block->m_tUncompressedData = 0; m_uCompressions++; - m_pUncompressedBlocks[leastRecentlyUsedBlockIndex] = block; + m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block = block; } else { - m_pUncompressedBlocks.push_back(block); + UncompressedBlock uncompressedBlock; + uncompressedBlock.block = block; + uncompressedBlock.data = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength]; + m_vecUncompressedBlockCache.push_back(uncompressedBlock); + uUncompressedBlockIndex = m_vecUncompressedBlockCache.size() - 1; } - block->uncompress(); + //VoxelType* pData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength]; + //VoxelType* pData = &(m_pUncompressedBlockData[uUncompressedBlockIndex][0]); + //VoxelType* pData = m_pUncompressedBlockData + (m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * uUncompressedBlockIndex); + block->uncompress(m_vecUncompressedBlockCache[uUncompressedBlockIndex].data); m_uUncompressions++; return block; } template - uint32_t Volume::sizeInChars(void) + uint32_t Volume::sizeInBytes(void) { - uint32_t uSizeInChars = 0; + uint32_t uSizeInBytes = 0; for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) { - uSizeInChars += m_pBlocks[i].sizeInChars(); + uSizeInBytes += m_pBlocks[i].sizeInBytes(); } - return uSizeInChars; + return uSizeInBytes; } }