Refactoring and tidying.

This commit is contained in:
David Williams 2011-02-10 22:43:34 +00:00
parent 7f831fb97a
commit 81d2bb6408
5 changed files with 104 additions and 115 deletions

View File

@ -502,9 +502,10 @@ int main(int argc, char *argv[])
openGLWidget.show(); openGLWidget.show();
//Create an empty volume and then place a sphere in it //Create an empty volume and then place a sphere in it
Volume<MaterialDensityPair44> volData(1024, 1280, 256); Volume<MaterialDensityPair44> volData(4096, 4096, 256);
//createSphereInVolume(volData, 30); //createSphereInVolume(volData, 30);
createPerlinTerrain(volData); createPerlinTerrain(volData);
//createPerlinVolumeSlow(volData);
volData.setBlockCacheSize(8); volData.setBlockCacheSize(8);
/*srand(12345); /*srand(12345);

View File

@ -33,11 +33,21 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
class Block class Block
{ {
template <typename LengthType>
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<LengthType>::max)();}
};
//Make VolumeSampler a friend //Make VolumeSampler a friend
friend class VolumeSampler<VoxelType>; friend class VolumeSampler<VoxelType>;
public: public:
Block(uint16_t uSideLength = 0); Block(uint16_t uSideLength = 0);
~Block();
uint16_t getSideLength(void) const; uint16_t getSideLength(void) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) 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 setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
void fill(VoxelType tValue); void fill(VoxelType tValue);
void resize(uint16_t uSideLength); void initialise(uint16_t uSideLength);
uint32_t sizeInChars(void); uint32_t sizeInBytes(void);
public: public:
void compress(void); void compress(void);
void uncompress(void); void uncompress(VoxelType* pData);
std::vector< RunlengthEntry<uint16_t> > m_vecCompressedData;
uint64_t m_uTimestamp;
VoxelType* m_tUncompressedData;
uint16_t m_uSideLength; uint16_t m_uSideLength;
uint8_t m_uSideLengthPower; uint8_t m_uSideLengthPower;
VoxelType* m_tUncompressedData;
bool m_bIsCompressed; bool m_bIsCompressed;
bool m_bIsUncompressedDataModified; bool m_bIsUncompressedDataModified;
uint64_t m_uTimestamp;
std::vector<uint16_t> runlengths;
std::vector<VoxelType> values;
private: private:
Block(const Block& rhs); Block(const Block& rhs);

View File

@ -43,7 +43,7 @@ namespace PolyVox
{ {
if(uSideLength != 0) if(uSideLength != 0)
{ {
resize(uSideLength); initialise(uSideLength);
} }
} }
@ -53,13 +53,6 @@ namespace PolyVox
assert(false); assert(false);
} }
template <typename VoxelType>
Block<VoxelType>::~Block()
{
delete[] m_tUncompressedData;
m_tUncompressedData = 0;
}
template <typename VoxelType> template <typename VoxelType>
Block<VoxelType>& Block<VoxelType>::operator=(const Block<VoxelType>& rhs) Block<VoxelType>& Block<VoxelType>::operator=(const Block<VoxelType>& rhs)
{ {
@ -124,11 +117,10 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::fill(VoxelType tValue) void Block<VoxelType>::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); 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; const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue); std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue);
@ -136,7 +128,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::resize(uint16_t uSideLength) void Block<VoxelType>::initialise(uint16_t uSideLength)
{ {
//Debug mode validation //Debug mode validation
assert(isPowerOf2(uSideLength)); assert(isPowerOf2(uSideLength));
@ -150,120 +142,77 @@ namespace PolyVox
//Compute the side length //Compute the side length
m_uSideLength = uSideLength; m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(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 <typename VoxelType> template <typename VoxelType>
uint32_t Block<VoxelType>::sizeInChars(void) uint32_t Block<VoxelType>::sizeInBytes(void)
{ {
uint32_t uSizeInChars = 0; //sizeof(Block<VoxelType>); uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
uSizeInBytes += m_vecCompressedData.size() * sizeof(RunlengthEntry);
if(m_tUncompressedData != 0) return uSizeInBytes;
{
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;
} }
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::compress(void) void Block<VoxelType>::compress(void)
{ {
assert(m_bIsCompressed == false); assert(m_bIsCompressed == false);
assert(m_tUncompressedData != 0);
//If the uncompressed data hasn't actually been //If the uncompressed data hasn't actually been
//modified then we don't need to redo the compression. //modified then we don't need to redo the compression.
if(m_bIsUncompressedDataModified) if(m_bIsUncompressedDataModified)
{ {
uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
runlengths.clear(); m_vecCompressedData.clear();
values.clear();
VoxelType current = m_tUncompressedData[0]; RunlengthEntry<uint16_t> entry;
uint16_t runLength = 1; entry.length = 1;
entry.value = m_tUncompressedData[0];
for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct) for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct)
{ {
VoxelType value = m_tUncompressedData[ct]; VoxelType value = m_tUncompressedData[ct];
if((value == current) && (runLength < (std::numeric_limits<uint16_t>::max)())) if((value == entry.value) && (entry.length < entry.maxRunlength()))
{ {
runLength++; entry.length++;
} }
else else
{ {
runlengths.push_back(runLength); m_vecCompressedData.push_back(entry);
values.push_back(current); entry.value = value;
current = value; entry.length = 1;
runLength = 1;
} }
} }
runlengths.push_back(runLength); m_vecCompressedData.push_back(entry);
values.push_back(current);
//Shrink the vectors to their contents (seems slow?): //Shrink the vectors to their contents (seems slow?):
//http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector //http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector
//C++0x may have a shrink_to_fit() function? //C++0x may have a shrink_to_fit() function?
//std::vector<uint8_t>(runlengths).swap(runlengths); //std::vector<RunlengthEntry>(m_vecCompressedData).swap(m_vecCompressedData);
//std::vector<VoxelType>(values).swap(values);
} }
assert(m_tUncompressedData != 0); //Flag the uncompressed data as no longer being used but don't delete it (we don't own it).
delete[] m_tUncompressedData;
m_tUncompressedData = 0; m_tUncompressedData = 0;
m_bIsCompressed = true; m_bIsCompressed = true;
} }
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::uncompress(void) void Block<VoxelType>::uncompress(VoxelType* pData)
{ {
assert(m_bIsCompressed == true); assert(m_bIsCompressed == true);
assert(m_tUncompressedData == 0); assert(m_tUncompressedData == 0);
m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; m_tUncompressedData = pData;
VoxelType* pUncompressedData = m_tUncompressedData; VoxelType* pUncompressedData = m_tUncompressedData;
for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct)
//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))
{ {
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 = m_vecCompressedData[ct].value;
pUncompressedData += runlengths[ct];
}
}
//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; ++pUncompressedData;
} }
} }
//}
m_bIsCompressed = false; m_bIsCompressed = false;
m_bIsUncompressedDataModified = false; m_bIsUncompressedDataModified = false;

View File

@ -118,6 +118,13 @@ namespace PolyVox
//Make VolumeSampler a friend //Make VolumeSampler a friend
friend class VolumeSampler<VoxelType>; friend class VolumeSampler<VoxelType>;
struct UncompressedBlock
{
Block<VoxelType>* block;
VoxelType* data;
};
public: public:
///Constructor ///Constructor
Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength = 32); 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 setBlockCacheSize(uint16_t uBlockCacheSize);
void clearBlockCache(void); void clearBlockCache(void);
uint32_t sizeInChars(void); uint32_t sizeInBytes(void);
public: public:
Block<VoxelType>* getUncompressedBlock(Block<VoxelType>* block) const; Block<VoxelType>* getUncompressedBlock(Block<VoxelType>* block) const;
Block<VoxelType> m_pBorderBlock; Block<VoxelType> m_pBorderBlock;
Block<VoxelType>* m_pBlocks; Block<VoxelType>* m_pBlocks;
mutable std::vector<Block<VoxelType>*> m_pUncompressedBlocks; //mutable std::vector<Block<VoxelType>*> m_pUncompressedBlocks;
uint16_t m_uBlockCacheSize; //mutable std::vector< std::vector<VoxelType> > m_pUncompressedBlockData;
//mutable VoxelType* m_pUncompressedBlockData;
mutable std::vector< UncompressedBlock > m_vecUncompressedBlockCache;
uint16_t m_uMaxUncompressedBlockCacheSize;
uint32_t m_uNoOfBlocksInVolume; uint32_t m_uNoOfBlocksInVolume;

View File

@ -49,13 +49,13 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength) Volume<VoxelType>::Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength)
:m_uTimestamper(0) :m_uTimestamper(0)
,m_uBlockCacheSize(256) ,m_uMaxUncompressedBlockCacheSize(256)
,m_uCompressions(0) ,m_uCompressions(0)
,m_uUncompressions(0) ,m_uUncompressions(0)
,m_uBlockSideLength(uBlockSideLength) ,m_uBlockSideLength(uBlockSideLength)
,m_pBlocks(0) ,m_pBlocks(0)
{ {
setBlockCacheSize(m_uBlockCacheSize); setBlockCacheSize(m_uMaxUncompressedBlockCacheSize);
//Create a volume of the right size. //Create a volume of the right size.
resize(uWidth, uHeight, uDepth, uBlockSideLength); resize(uWidth, uHeight, uDepth, uBlockSideLength);
@ -272,13 +272,13 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::clearBlockCache(void) void Volume<VoxelType>::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_uCompressions++;
} }
m_vecUncompressedBlockCache.clear();
m_pUncompressedBlocks.clear();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -350,11 +350,11 @@ namespace PolyVox
m_pBlocks = new Block<VoxelType>[m_uNoOfBlocksInVolume]; m_pBlocks = new Block<VoxelType>[m_uNoOfBlocksInVolume];
for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) 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 //Create the border block
m_pBorderBlock.resize(uBlockSideLength); m_pBorderBlock.initialise(uBlockSideLength);
Block<VoxelType>* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock); Block<VoxelType>* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock);
pUncompressedBorderBlock->fill(VoxelType()); pUncompressedBorderBlock->fill(VoxelType());
@ -369,7 +369,19 @@ namespace PolyVox
{ {
clearBlockCache(); 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 <typename VoxelType> template <typename VoxelType>
@ -384,43 +396,52 @@ namespace PolyVox
uint32_t uUncompressedBlockIndex = 100000000; uint32_t uUncompressedBlockIndex = 100000000;
assert(m_pUncompressedBlocks.size() <= m_uBlockCacheSize); assert(m_vecUncompressedBlockCache.size() <= m_uMaxUncompressedBlockCacheSize);
if(m_pUncompressedBlocks.size() == m_uBlockCacheSize) if(m_vecUncompressedBlockCache.size() == m_uMaxUncompressedBlockCacheSize)
{ {
int32_t leastRecentlyUsedBlockIndex = -1; int32_t leastRecentlyUsedBlockIndex = -1;
uint64_t uLeastRecentTimestamp = 1000000000000000; 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; leastRecentlyUsedBlockIndex = ct;
} }
} }
m_pUncompressedBlocks[leastRecentlyUsedBlockIndex]->compress(); uUncompressedBlockIndex = leastRecentlyUsedBlockIndex;
m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block->compress();
m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block->m_tUncompressedData = 0;
m_uCompressions++; m_uCompressions++;
m_pUncompressedBlocks[leastRecentlyUsedBlockIndex] = block; m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].block = block;
} }
else 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++; m_uUncompressions++;
return block; return block;
} }
template <typename VoxelType> template <typename VoxelType>
uint32_t Volume<VoxelType>::sizeInChars(void) uint32_t Volume<VoxelType>::sizeInBytes(void)
{ {
uint32_t uSizeInChars = 0; uint32_t uSizeInBytes = 0;
for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i)
{ {
uSizeInChars += m_pBlocks[i].sizeInChars(); uSizeInBytes += m_pBlocks[i].sizeInBytes();
} }
return uSizeInChars; return uSizeInBytes;
} }
} }