Some refactoring of the volume.

This commit is contained in:
David Williams 2011-03-18 23:54:11 +00:00
parent ef185d79a0
commit 3cc2e4383f
5 changed files with 51 additions and 62 deletions

View File

@ -64,9 +64,6 @@ namespace PolyVox
//---------- Volume ---------- //---------- Volume ----------
template <typename VoxelType> class Volume; template <typename VoxelType> class Volume;
typedef Volume<float> FloatVolume;
typedef Volume<uint8_t> UInt8Volume;
typedef Volume<uint16_t> UInt16Volume;
//--------------------------------- //---------------------------------
//---------- Mesh ---------- //---------- Mesh ----------

View File

@ -70,9 +70,6 @@ namespace PolyVox
uint8_t m_uSideLengthPower; uint8_t m_uSideLengthPower;
bool m_bIsCompressed; bool m_bIsCompressed;
bool m_bIsUncompressedDataModified; bool m_bIsUncompressedDataModified;
uint32_t m_uTimestamp;
uint32_t m_uUncompressedIndex;
}; };
} }

View File

@ -39,8 +39,6 @@ namespace PolyVox
,m_tUncompressedData(NULL) ,m_tUncompressedData(NULL)
,m_bIsCompressed(true) ,m_bIsCompressed(true)
,m_bIsUncompressedDataModified(true) ,m_bIsUncompressedDataModified(true)
,m_uTimestamp(0)
,m_uUncompressedIndex((std::numeric_limits<uint32_t>::max)())
{ {
if(uSideLength != 0) if(uSideLength != 0)
{ {

View File

@ -116,11 +116,19 @@ namespace PolyVox
// Make the ConstVolumeProxy a friend // Make the ConstVolumeProxy a friend
friend class ConstVolumeProxy<VoxelType>; friend class ConstVolumeProxy<VoxelType>;
struct UncompressedBlock struct LoadedBlock
{ {
Vector3DInt32 v3dBlockIndex; public:
VoxelType* data; LoadedBlock(uint16_t uSideLength = 0)
:block(uSideLength)
,uncompressedData(0)
,timestamp(0)
{
}
Block<VoxelType> block;
VoxelType* uncompressedData;
uint32_t timestamp;
}; };
public: public:
@ -182,22 +190,21 @@ namespace PolyVox
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler; polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler;
private: private:
Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType> >::iterator itBlock) const; void eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const;
/// this function can be called by dataRequiredHandler without causing any weird effects /// this function can be called by dataRequiredHandler without causing any weird effects
bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const; bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const;
//The block data //The block data
mutable std::map<Vector3DInt32, Block<VoxelType> > m_pBlocks; mutable std::map<Vector3DInt32, LoadedBlock > m_pBlocks;
//The cache of uncompressed blocks. The uncompressed block data and the timestamps are stored here rather //The cache of uncompressed blocks. The uncompressed block data and the timestamps are stored here rather
//than in the Block class. This is so that in the future each VolumeIterator might to maintain its own cache //than in the Block class. This is so that in the future each VolumeIterator might to maintain its own cache
//of blocks. However, this could mean the same block data is uncompressed and modified in more than one //of blocks. However, this could mean the same block data is uncompressed and modified in more than one
//location in memory... could be messy with threading. //location in memory... could be messy with threading.
mutable std::vector< UncompressedBlock > m_vecUncompressedBlockCache; mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache;
mutable std::vector<uint32_t> m_pUncompressedTimestamps;
mutable uint32_t m_uTimestamper; mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable Block<VoxelType>* m_pLastAccessedBlock; mutable LoadedBlock* m_pLastAccessedBlock;
uint32_t m_uMaxUncompressedBlockCacheSize; uint32_t m_uMaxUncompressedBlockCacheSize;
uint32_t m_uMaxBlocksLoaded; uint32_t m_uMaxBlocksLoaded;
@ -220,11 +227,6 @@ namespace PolyVox
int32_t m_uShortestSideLength; int32_t m_uShortestSideLength;
float m_fDiagonalLength; float m_fDiagonalLength;
}; };
//Some handy typedefs
typedef Volume<float> FloatVolume;
typedef Volume<uint8_t> UInt8Volume;
typedef Volume<uint16_t> UInt16Volume;
} }
#include "Volume.inl" #include "Volume.inl"

View File

@ -99,7 +99,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::~Volume() Volume<VoxelType>::~Volume()
{ {
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator i; typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i = m_pBlocks.begin()) { for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i = m_pBlocks.begin()) {
eraseBlock(i); eraseBlock(i);
} }
@ -255,11 +255,14 @@ namespace PolyVox
if(uMaxBlocks < m_pBlocks.size()) { if(uMaxBlocks < m_pBlocks.size()) {
std::cout << uMaxBlocks << ", " << m_pBlocks.size() << ", " << m_pBlocks.size() - uMaxBlocks << std::endl; std::cout << uMaxBlocks << ", " << m_pBlocks.size() << ", " << m_pBlocks.size() - uMaxBlocks << std::endl;
// we need to unload some blocks // we need to unload some blocks
for(int j = 0; j < m_pBlocks.size() - uMaxBlocks; j++) { for(int j = 0; j < m_pBlocks.size() - uMaxBlocks; j++)
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator i; {
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator itUnloadBlock = m_pBlocks.begin(); typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) { typename std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin();
if(i->second.m_uTimestamp < itUnloadBlock->second.m_uTimestamp) { for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
if(i->second.timestamp < itUnloadBlock->second.timestamp)
{
itUnloadBlock = i; itUnloadBlock = i;
} }
} }
@ -324,8 +327,8 @@ namespace PolyVox
{ {
for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++)
{ {
m_pBlocks[m_vecUncompressedBlockCache[ct].v3dBlockIndex].compress(); m_vecUncompressedBlockCache[ct]->block.compress();
delete[] m_vecUncompressedBlockCache[ct].data; delete[] m_vecUncompressedBlockCache[ct]->uncompressedData;
} }
m_vecUncompressedBlockCache.clear(); m_vecUncompressedBlockCache.clear();
} }
@ -375,7 +378,6 @@ namespace PolyVox
//Clear the previous data //Clear the previous data
m_pBlocks.clear(); m_pBlocks.clear();
m_pUncompressedTimestamps.clear();
//Compute the block side length //Compute the block side length
m_uBlockSideLength = uBlockSideLength; m_uBlockSideLength = uBlockSideLength;
@ -383,9 +385,6 @@ namespace PolyVox
//Clear the previous data //Clear the previous data
m_pBlocks.clear(); m_pBlocks.clear();
m_pUncompressedTimestamps.clear();
m_pUncompressedTimestamps.resize(m_uMaxUncompressedBlockCacheSize, 0);
//Create the border block //Create the border block
m_pUncompressedBorderData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength]; m_pUncompressedBorderData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength];
@ -398,7 +397,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType> >::iterator itBlock) const void Volume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const
{ {
if(dataOverflowHandler) if(dataOverflowHandler)
{ {
@ -449,10 +448,10 @@ namespace PolyVox
//This check should also provide a significant speed boost as usually it is true. //This check should also provide a significant speed boost as usually it is true.
if((v3dBlockPos == m_v3dLastAccessedBlockPos) && (m_pLastAccessedBlock != 0)) if((v3dBlockPos == m_v3dLastAccessedBlockPos) && (m_pLastAccessedBlock != 0))
{ {
return m_pLastAccessedBlock; return &(m_pLastAccessedBlock->block);
} }
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator itBlock = m_pBlocks.find(v3dBlockPos); typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock = m_pBlocks.find(v3dBlockPos);
// check whether the block is already loaded // check whether the block is already loaded
if(itBlock == m_pBlocks.end()) if(itBlock == m_pBlocks.end())
{ {
@ -461,11 +460,11 @@ namespace PolyVox
if(m_pBlocks.size() == m_uMaxBlocksLoaded) if(m_pBlocks.size() == m_uMaxBlocksLoaded)
{ {
// find the least recently used block // find the least recently used block
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator i; typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator itUnloadBlock = m_pBlocks.begin(); typename std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{ {
if(i->second.m_uTimestamp < itUnloadBlock->second.m_uTimestamp) if(i->second.timestamp < itUnloadBlock->second.timestamp)
{ {
itUnloadBlock = i; itUnloadBlock = i;
} }
@ -476,7 +475,7 @@ namespace PolyVox
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1);
// create the new block // create the new block
Block<VoxelType> newBlock(m_uBlockSideLength); LoadedBlock newBlock(m_uBlockSideLength);
itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first;
// fill it with data (well currently fill it with nothingness) // fill it with data (well currently fill it with nothingness)
@ -494,16 +493,15 @@ namespace PolyVox
m_v3dLastAccessedBlockPos = v3dBlockPos; m_v3dLastAccessedBlockPos = v3dBlockPos;
//Get the block //Get the block
Block<VoxelType>* block = &(itBlock->second); LoadedBlock* block = &(itBlock->second);
m_uTimestamper++; m_uTimestamper++;
block->m_uTimestamp = m_uTimestamper; block->timestamp = m_uTimestamper;
if(block->m_bIsCompressed == false) if(block->block.m_bIsCompressed == false)
{ {
m_pUncompressedTimestamps[block->m_uUncompressedIndex] = m_uTimestamper;
m_pLastAccessedBlock = block; m_pLastAccessedBlock = block;
return block; return &(block->block);
} }
//Currently we find the oldest block by iterating over the whole array. Of course we could store the blocks sorted by //Currently we find the oldest block by iterating over the whole array. Of course we could store the blocks sorted by
@ -517,31 +515,27 @@ namespace PolyVox
uint32_t uLeastRecentTimestamp = (std::numeric_limits<uint32_t>::max)(); // you said not int64 ;) uint32_t uLeastRecentTimestamp = (std::numeric_limits<uint32_t>::max)(); // you said not int64 ;)
for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++)
{ {
if(m_pUncompressedTimestamps[ct] < uLeastRecentTimestamp) if(m_vecUncompressedBlockCache[ct]->timestamp < uLeastRecentTimestamp)
{ {
uLeastRecentTimestamp = m_pUncompressedTimestamps[ct]; uLeastRecentTimestamp = m_vecUncompressedBlockCache[ct]->timestamp;
leastRecentlyUsedBlockIndex = ct; leastRecentlyUsedBlockIndex = ct;
} }
} }
uUncompressedBlockIndex = leastRecentlyUsedBlockIndex; uUncompressedBlockIndex = leastRecentlyUsedBlockIndex;
m_pBlocks[m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].v3dBlockIndex].compress(); m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress();
m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex].v3dBlockIndex = v3dBlockPos; m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->uncompressedData = 0;
} }
else else
{ {
UncompressedBlock uncompressedBlock; block->uncompressedData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength];
//uncompressedBlock.block = block; m_vecUncompressedBlockCache.push_back(block);
uncompressedBlock.v3dBlockIndex = v3dBlockPos;
uncompressedBlock.data = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength];
m_vecUncompressedBlockCache.push_back(uncompressedBlock);
uUncompressedBlockIndex = m_vecUncompressedBlockCache.size() - 1; uUncompressedBlockIndex = m_vecUncompressedBlockCache.size() - 1;
} }
block->m_uUncompressedIndex = uUncompressedBlockIndex; block->block.uncompress(block->uncompressedData);
block->uncompress(m_vecUncompressedBlockCache[uUncompressedBlockIndex].data);
m_pLastAccessedBlock = block; m_pLastAccessedBlock = block;
return block; return &(block->block);
} }
template <typename VoxelType> template <typename VoxelType>
@ -558,15 +552,16 @@ namespace PolyVox
uint32_t uSizeInBytes = sizeof(Volume); uint32_t uSizeInBytes = sizeof(Volume);
//Memory used by the blocks //Memory used by the blocks
typename std::map<Vector3DInt32, Block<VoxelType> >::iterator i; typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) { for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
i->second.calculateSizeInBytes(); {
//Inaccurate - account for rest of loaded block.
uSizeInBytes += i->second.block.calculateSizeInBytes();
} }
//Memory used by the block cache. //Memory used by the block cache.
uSizeInBytes += m_vecUncompressedBlockCache.capacity() * sizeof(UncompressedBlock); uSizeInBytes += m_vecUncompressedBlockCache.capacity() * sizeof(LoadedBlock);
uSizeInBytes += m_vecUncompressedBlockCache.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); uSizeInBytes += m_vecUncompressedBlockCache.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
uSizeInBytes += m_pUncompressedTimestamps.capacity() * sizeof(uint32_t);
//Memory used by border data. //Memory used by border data.
if(m_pUncompressedBorderData) if(m_pUncompressedBorderData)