Work on making paging optional.

This commit is contained in:
David Williams 2011-03-19 19:01:04 +00:00
parent 3cc2e4383f
commit 60dbfd9335
7 changed files with 157 additions and 88 deletions

View File

@ -559,17 +559,17 @@ 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(128); Volume<MaterialDensityPair44> volData(&load, &unload, 128);
//If these two lines don't compile, please try commenting them out and using the two lines after //If these two lines don't compile, please try commenting them out and using the two lines after
//(you will need Boost for this). If you have to do this then please let us know in the forums as //(you will need Boost for this). If you have to do this then please let us know in the forums as
//we rely on community feedback to keep the Boost version running. //we rely on community feedback to keep the Boost version running.
volData.dataRequiredHandler = &load; //volData.dataRequiredHandler = &load;
volData.dataOverflowHandler = &unload; //volData.dataOverflowHandler = &unload;
//volData.dataRequiredHandler = polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2); //volData.dataRequiredHandler = polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2);
//volData.dataOverflowHandler = polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2); //volData.dataOverflowHandler = polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2);
volData.setBlockCacheSize(4096); //volData.setMaxNumberOfUncompressedBlocks(4096);
//createSphereInVolume(volData, 30); //createSphereInVolume(volData, 30);
//createPerlinTerrain(volData); //createPerlinTerrain(volData);
//createPerlinVolumeSlow(volData); //createPerlinVolumeSlow(volData);

View File

@ -37,7 +37,7 @@ freely, subject to the following restrictions:
#include "OpenGLVertexBufferObjectSupport.h" #include "OpenGLVertexBufferObjectSupport.h"
#include "Shapes.h" #include "Shapes.h"
const uint16_t g_uVolumeSideLength = 128; const int32_t g_uVolumeSideLength = 128;
class OpenGLWidget : public QGLWidget class OpenGLWidget : public QGLWidget
{ {

View File

@ -62,7 +62,7 @@ namespace PolyVox
public: public:
void compress(void); void compress(void);
void uncompress(VoxelType* pData); void uncompress(void);
std::vector< RunlengthEntry<uint16_t> > m_vecCompressedData; std::vector< RunlengthEntry<uint16_t> > m_vecCompressedData;
VoxelType* m_tUncompressedData; VoxelType* m_tUncompressedData;

View File

@ -36,7 +36,7 @@ namespace PolyVox
Block<VoxelType>::Block(uint16_t uSideLength) Block<VoxelType>::Block(uint16_t uSideLength)
:m_uSideLength(0) :m_uSideLength(0)
,m_uSideLengthPower(0) ,m_uSideLengthPower(0)
,m_tUncompressedData(NULL) ,m_tUncompressedData(0)
,m_bIsCompressed(true) ,m_bIsCompressed(true)
,m_bIsUncompressedDataModified(true) ,m_bIsUncompressedDataModified(true)
{ {
@ -103,14 +103,17 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::fill(VoxelType tValue) void Block<VoxelType>::fill(VoxelType tValue)
{ {
if(!m_bIsCompressed) { if(!m_bIsCompressed)
{
//The memset *may* be faster than the std::fill(), but it doesn't compile nicely //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. //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);
m_bIsUncompressedDataModified = true; m_bIsUncompressedDataModified = true;
} else { }
else
{
RunlengthEntry<uint16_t> rle; RunlengthEntry<uint16_t> rle;
rle.length = m_uSideLength*m_uSideLength*m_uSideLength; rle.length = m_uSideLength*m_uSideLength*m_uSideLength;
rle.value = tValue; rle.value = tValue;
@ -186,17 +189,18 @@ namespace PolyVox
std::vector< RunlengthEntry<uint16_t> >(m_vecCompressedData).swap(m_vecCompressedData); std::vector< RunlengthEntry<uint16_t> >(m_vecCompressedData).swap(m_vecCompressedData);
} }
//Flag the uncompressed data as no longer being used but don't delete it (we don't own it). //Flag the uncompressed data as no longer being used.
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(VoxelType* pData) void Block<VoxelType>::uncompress(void)
{ {
assert(m_bIsCompressed == true); assert(m_bIsCompressed == true);
assert(m_tUncompressedData == 0); assert(m_tUncompressedData == 0);
m_tUncompressedData = pData; m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
VoxelType* pUncompressedData = m_tUncompressedData; VoxelType* pUncompressedData = m_tUncompressedData;
for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct) for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct)

View File

@ -121,23 +121,40 @@ namespace PolyVox
public: public:
LoadedBlock(uint16_t uSideLength = 0) LoadedBlock(uint16_t uSideLength = 0)
:block(uSideLength) :block(uSideLength)
,uncompressedData(0)
,timestamp(0) ,timestamp(0)
{ {
} }
Block<VoxelType> block; Block<VoxelType> block;
VoxelType* uncompressedData;
uint32_t timestamp; uint32_t timestamp;
}; };
public: public:
/// Constructor /// Constructor
Volume(uint16_t uBlockSideLength = 32); Volume
(
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler,
uint16_t uBlockSideLength = 32
);
/// Constructor /// Constructor
Volume(const Region& regValid, uint16_t uBlockSideLength = 32); Volume
(
const Region& regValid,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler = 0,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler = 0,
bool bStreamingEnabled = false,
uint16_t uBlockSideLength = 32
);
/// Constructor /// Constructor
Volume(int32_t uWidth, int32_t uHeight, int32_t uDepth, uint16_t uBlockSideLength = 32); Volume
(
int32_t uWidth, int32_t uHeight, int32_t uDepth,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler = 0,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler = 0,
bool bStreamingEnabled = false,
uint16_t uBlockSideLength = 32
);
/// Destructor /// Destructor
~Volume(); ~Volume();
@ -163,9 +180,9 @@ namespace PolyVox
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Sets the number of blocks for which uncompressed data is stored. /// Sets the number of blocks for which uncompressed data is stored.
void setBlockCacheSize(uint16_t uBlockCacheSize); void setMaxNumberOfUncompressedBlocks(uint16_t uMaxNumberOfUncompressedBlocks);
/// Sets the number of blocks which can be in memory before unload is called /// Sets the number of blocks which can be in memory before unload is called
void setMaxBlocksLoaded(uint16_t uBlockCacheSize); void setMaxNumberOfBlocksInMemory(uint16_t uMaxNumberOfBlocksInMemory);
/// Sets the value used for voxels which are outside the volume /// Sets the value used for voxels which are outside the volume
void setBorderValue(const VoxelType& tBorder); void setBorderValue(const VoxelType& tBorder);
/// Sets the voxel at an <tt>x,y,z</tt> position /// Sets the voxel at an <tt>x,y,z</tt> position
@ -179,19 +196,21 @@ namespace PolyVox
/// Deprecated - I don't think we should expose this function? Let us know if you disagree... /// Deprecated - I don't think we should expose this function? Let us know if you disagree...
void resize(const Region& regValidRegion, uint16_t uBlockSideLength); void resize(const Region& regValidRegion, uint16_t uBlockSideLength);
private:
/// gets called when a new region is allocated and needs to be filled /// gets called when a new region is allocated and needs to be filled
/// NOTE: accessing ANY voxels outside this region during the process of this function /// NOTE: accessing ANY voxels outside this region during the process of this function
/// is absolutely unsafe /// is absolutely unsafe
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler; polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> m_funcDataRequiredHandler;
/// gets called when a Region needs to be stored by the user, because Volume will erase it right after /// gets called when a Region needs to be stored by the user, because Volume will erase it right after
/// this function returns /// this function returns
/// NOTE: accessing ANY voxels outside this region during the process of this function /// NOTE: accessing ANY voxels outside this region during the process of this function
/// is absolutely unsafe /// is absolutely unsafe
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler; polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> m_funcDataOverflowHandler;
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, LoadedBlock >::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 m_funcDataRequiredHandler 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
@ -204,9 +223,9 @@ namespace PolyVox
mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache; mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache;
mutable uint32_t m_uTimestamper; mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable LoadedBlock* m_pLastAccessedBlock; mutable Block<VoxelType>* m_pLastAccessedBlock;
uint32_t m_uMaxUncompressedBlockCacheSize; uint32_t m_uMaxNumberOfUncompressedBlocks;
uint32_t m_uMaxBlocksLoaded; uint32_t m_uMaxNumberOfBlocksInMemory;
//We don't store an actual Block for the border, just the uncompressed data. This is partly because the border //We don't store an actual Block for the border, just the uncompressed data. This is partly because the border
//block does not have a position (so can't be passed to getUncompressedBlock()) and partly because there's a //block does not have a position (so can't be passed to getUncompressedBlock()) and partly because there's a
@ -226,6 +245,8 @@ namespace PolyVox
int32_t m_uLongestSideLength; int32_t m_uLongestSideLength;
int32_t m_uShortestSideLength; int32_t m_uShortestSideLength;
float m_fDiagonalLength; float m_fDiagonalLength;
bool m_bStreamingEnabled;
}; };
} }

View File

@ -49,8 +49,16 @@ namespace PolyVox
/// the default if you are not sure what to choose here. /// the default if you are not sure what to choose here.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::Volume(uint16_t uBlockSideLength) Volume<VoxelType>::Volume
(
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler,
uint16_t uBlockSideLength
)
{ {
m_funcDataRequiredHandler = dataRequiredHandler;
m_funcDataOverflowHandler = dataOverflowHandler;
m_bStreamingEnabled = true;
//Create a volume of the right size. //Create a volume of the right size.
resize(Region::MaxRegion,uBlockSideLength); resize(Region::MaxRegion,uBlockSideLength);
} }
@ -68,8 +76,19 @@ namespace PolyVox
/// the default if you are not sure what to choose here. /// the default if you are not sure what to choose here.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::Volume(int32_t uWidth, int32_t uHeight, int32_t uDepth, uint16_t uBlockSideLength) Volume<VoxelType>::Volume
(
int32_t uWidth, int32_t uHeight, int32_t uDepth,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler,
bool bStreamingEnabled,
uint16_t uBlockSideLength
)
{ {
m_funcDataRequiredHandler = dataRequiredHandler;
m_funcDataOverflowHandler = dataOverflowHandler;
m_bStreamingEnabled = bStreamingEnabled;
Region regValid(Vector3DInt32(0,0,0), Vector3DInt32(uWidth - 1,uHeight - 1,uDepth - 1)); Region regValid(Vector3DInt32(0,0,0), Vector3DInt32(uWidth - 1,uHeight - 1,uDepth - 1));
resize(Region(Vector3DInt32(0,0,0), Vector3DInt32(uWidth - 1,uHeight - 1,uDepth - 1)), uBlockSideLength); resize(Region(Vector3DInt32(0,0,0), Vector3DInt32(uWidth - 1,uHeight - 1,uDepth - 1)), uBlockSideLength);
} }
@ -87,8 +106,19 @@ namespace PolyVox
/// the default if you are not sure what to choose here. /// the default if you are not sure what to choose here.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::Volume(const Region& regValid, uint16_t uBlockSideLength) Volume<VoxelType>::Volume
(
const Region& regValid,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataRequiredHandler,
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler,
bool bStreamingEnabled,
uint16_t uBlockSideLength
)
{ {
m_funcDataRequiredHandler = dataRequiredHandler;
m_funcDataOverflowHandler = dataOverflowHandler;
m_bStreamingEnabled = bStreamingEnabled;
//Create a volume of the right size. //Create a volume of the right size.
resize(regValid,uBlockSideLength); resize(regValid,uBlockSideLength);
} }
@ -99,7 +129,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
Volume<VoxelType>::~Volume() Volume<VoxelType>::~Volume()
{ {
typename std::map<Vector3DInt32, LoadedBlock >::iterator i; 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);
} }
@ -238,11 +268,11 @@ namespace PolyVox
/// \param uBlockCacheSize The number of blocks for which uncompressed data can be cached. /// \param uBlockCacheSize The number of blocks for which uncompressed data can be cached.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::setBlockCacheSize(uint16_t uBlockCacheSize) void Volume<VoxelType>::setMaxNumberOfUncompressedBlocks(uint16_t uMaxNumberOfUncompressedBlocks)
{ {
clearBlockCache(); clearBlockCache();
m_uMaxUncompressedBlockCacheSize = uBlockCacheSize; m_uMaxNumberOfUncompressedBlocks = uMaxNumberOfUncompressedBlocks;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -250,15 +280,18 @@ namespace PolyVox
/// \param uMaxBlocks The number of blocks /// \param uMaxBlocks The number of blocks
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::setMaxBlocksLoaded(uint16_t uMaxBlocks) void Volume<VoxelType>::setMaxNumberOfBlocksInMemory(uint16_t uMaxNumberOfBlocksInMemory)
{ {
if(uMaxBlocks < m_pBlocks.size()) { //FIXME? - I'm concerned about the logic in here... particularly the
std::cout << uMaxBlocks << ", " << m_pBlocks.size() << ", " << m_pBlocks.size() - uMaxBlocks << std::endl; //way timestamps are handled. Perhaps extract all timestamps, sort them,
//identify the cut-off point, and then discard those above it?
if(m_pBlocks.size() > uMaxNumberOfBlocksInMemory)
{
// 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() - uMaxNumberOfBlocksInMemory; j++)
{ {
typename std::map<Vector3DInt32, LoadedBlock >::iterator i; std::map<Vector3DInt32, LoadedBlock >::iterator i;
typename std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin(); 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.timestamp < itUnloadBlock->second.timestamp) if(i->second.timestamp < itUnloadBlock->second.timestamp)
@ -269,7 +302,7 @@ namespace PolyVox
eraseBlock(itUnloadBlock); eraseBlock(itUnloadBlock);
} }
} }
m_uMaxBlocksLoaded = uMaxBlocks; m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -328,7 +361,6 @@ namespace PolyVox
for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++)
{ {
m_vecUncompressedBlockCache[ct]->block.compress(); m_vecUncompressedBlockCache[ct]->block.compress();
delete[] m_vecUncompressedBlockCache[ct]->uncompressedData;
} }
m_vecUncompressedBlockCache.clear(); m_vecUncompressedBlockCache.clear();
} }
@ -362,10 +394,10 @@ namespace PolyVox
} }
m_uTimestamper = 0; m_uTimestamper = 0;
m_uMaxUncompressedBlockCacheSize = 256; m_uMaxNumberOfUncompressedBlocks = 16;
m_uBlockSideLength = uBlockSideLength; m_uBlockSideLength = uBlockSideLength;
m_pUncompressedBorderData = 0; m_pUncompressedBorderData = 0;
m_uMaxBlocksLoaded = 4096; m_uMaxNumberOfBlocksInMemory = 1024;
m_v3dLastAccessedBlockPos = Vector3DInt32((std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)()); //An invalid index m_v3dLastAccessedBlockPos = Vector3DInt32((std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)()); //An invalid index
m_pLastAccessedBlock = 0; m_pLastAccessedBlock = 0;
@ -374,7 +406,7 @@ namespace PolyVox
m_regValidRegionInBlocks.setLowerCorner(m_regValidRegion.getLowerCorner() / static_cast<int32_t>(uBlockSideLength)); m_regValidRegionInBlocks.setLowerCorner(m_regValidRegion.getLowerCorner() / static_cast<int32_t>(uBlockSideLength));
m_regValidRegionInBlocks.setUpperCorner(m_regValidRegion.getUpperCorner() / static_cast<int32_t>(uBlockSideLength)); m_regValidRegionInBlocks.setUpperCorner(m_regValidRegion.getUpperCorner() / static_cast<int32_t>(uBlockSideLength));
setBlockCacheSize(m_uMaxUncompressedBlockCacheSize); setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks);
//Clear the previous data //Clear the previous data
m_pBlocks.clear(); m_pBlocks.clear();
@ -399,7 +431,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const void Volume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const
{ {
if(dataOverflowHandler) if(m_funcDataOverflowHandler)
{ {
Vector3DInt32 v3dPos = itBlock->first; Vector3DInt32 v3dPos = itBlock->first;
Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower); Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower);
@ -408,7 +440,7 @@ namespace PolyVox
Region reg(v3dLower, v3dUpper); Region reg(v3dLower, v3dUpper);
ConstVolumeProxy<VoxelType> ConstVolumeProxy(*this, reg); ConstVolumeProxy<VoxelType> ConstVolumeProxy(*this, reg);
dataOverflowHandler(ConstVolumeProxy, reg); m_funcDataOverflowHandler(ConstVolumeProxy, reg);
} }
m_pBlocks.erase(itBlock); m_pBlocks.erase(itBlock);
} }
@ -448,68 +480,76 @@ 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->block); assert(m_pLastAccessedBlock->m_tUncompressedData);
return m_pLastAccessedBlock;
} }
typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock = m_pBlocks.find(v3dBlockPos); 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())
{ {
// it is not loaded //The block is not in the map, so we will have to create a new block and add it.
// check wether another block needs to be unloaded before this one can be loaded //Before we do so, we might want to dump some existing data to make space. We
if(m_pBlocks.size() == m_uMaxBlocksLoaded) //Only do this if paging is enabled.
if(m_bStreamingEnabled)
{ {
// find the least recently used block // check wether another block needs to be unloaded before this one can be loaded
typename std::map<Vector3DInt32, LoadedBlock >::iterator i; if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory)
typename std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{ {
if(i->second.timestamp < itUnloadBlock->second.timestamp) // find the least recently used block
std::map<Vector3DInt32, LoadedBlock >::iterator i;
std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{ {
itUnloadBlock = i; if(i->second.timestamp < itUnloadBlock->second.timestamp)
{
itUnloadBlock = i;
}
} }
eraseBlock(itUnloadBlock);
} }
eraseBlock(itUnloadBlock);
} }
Vector3DInt32 v3dLower(v3dBlockPos.getX() << m_uBlockSideLengthPower, v3dBlockPos.getY() << m_uBlockSideLengthPower, v3dBlockPos.getZ() << m_uBlockSideLengthPower);
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1);
// create the new block // create the new block
LoadedBlock 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) //We have created the new block. If paging is enabled it should be used to
// "load" will actually call setVoxel, which will in turn call this function again but the block will be found //fill in the required data. Otherwise it is just left in the default state.
// so this if(itBlock == m_pBlocks.end()) never is entered if(m_bStreamingEnabled)
if(dataRequiredHandler)
{ {
Region reg(v3dLower, v3dUpper); if(m_funcDataRequiredHandler)
ConstVolumeProxy<VoxelType> ConstVolumeProxy(*this, reg); {
dataRequiredHandler(ConstVolumeProxy, reg); // "load" will actually call setVoxel, which will in turn call this function again but the block will be found
// so this if(itBlock == m_pBlocks.end()) never is entered
//FIXME - can we pass the block around so that we don't have to find it again when we recursively call this function?
Vector3DInt32 v3dLower(v3dBlockPos.getX() << m_uBlockSideLengthPower, v3dBlockPos.getY() << m_uBlockSideLengthPower, v3dBlockPos.getZ() << m_uBlockSideLengthPower);
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1);
Region reg(v3dLower, v3dUpper);
ConstVolumeProxy<VoxelType> ConstVolumeProxy(*this, reg);
m_funcDataRequiredHandler(ConstVolumeProxy, reg);
}
} }
} }
//Get the block and mark that we accessed it
LoadedBlock& loadedBlock = itBlock->second;
loadedBlock.timestamp = ++m_uTimestamper;
m_v3dLastAccessedBlockPos = v3dBlockPos; m_v3dLastAccessedBlockPos = v3dBlockPos;
m_pLastAccessedBlock = &(loadedBlock.block);
//Get the block if(loadedBlock.block.m_bIsCompressed == false)
LoadedBlock* block = &(itBlock->second); {
assert(m_pLastAccessedBlock->m_tUncompressedData);
m_uTimestamper++; return m_pLastAccessedBlock;
block->timestamp = m_uTimestamper;
if(block->block.m_bIsCompressed == false)
{
m_pLastAccessedBlock = 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
//timestamp (set, priority_queue, etc) but then we'll need to move them around as the timestamp changes. Can come back //timestamp (set, priority_queue, etc) but then we'll need to move them around as the timestamp changes. Can come back
//to this if it proves to be a bottleneck (compraed to the cost of actually doing the compression/decompression). //to this if it proves to be a bottleneck (compraed to the cost of actually doing the compression/decompression).
uint32_t uUncompressedBlockIndex = (std::numeric_limits<uint32_t>::max)(); uint32_t uUncompressedBlockIndex = (std::numeric_limits<uint32_t>::max)();
assert(m_vecUncompressedBlockCache.size() <= m_uMaxUncompressedBlockCacheSize); assert(m_vecUncompressedBlockCache.size() <= m_uMaxNumberOfUncompressedBlocks);
if(m_vecUncompressedBlockCache.size() == m_uMaxUncompressedBlockCacheSize) if(m_vecUncompressedBlockCache.size() == m_uMaxNumberOfUncompressedBlocks)
{ {
int32_t leastRecentlyUsedBlockIndex = -1; int32_t leastRecentlyUsedBlockIndex = -1;
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 ;)
@ -524,18 +564,22 @@ namespace PolyVox
uUncompressedBlockIndex = leastRecentlyUsedBlockIndex; uUncompressedBlockIndex = leastRecentlyUsedBlockIndex;
m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress(); m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress();
m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->uncompressedData = 0; m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex] = &loadedBlock;
//m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.m_tUncompressedData = 0;
} }
else else
{ {
block->uncompressedData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength]; //loadedBlock.block.m_tUncompressedData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength];
m_vecUncompressedBlockCache.push_back(block); m_vecUncompressedBlockCache.push_back(&loadedBlock);
uUncompressedBlockIndex = m_vecUncompressedBlockCache.size() - 1; uUncompressedBlockIndex = m_vecUncompressedBlockCache.size() - 1;
} }
block->block.uncompress(block->uncompressedData);
loadedBlock.block.uncompress();
//m_vecUncompressedBlockCache.push_back(&loadedBlock);
m_pLastAccessedBlock = block; m_pLastAccessedBlock = &(loadedBlock.block);
return &(block->block); assert(m_pLastAccessedBlock->m_tUncompressedData);
return m_pLastAccessedBlock;
} }
template <typename VoxelType> template <typename VoxelType>
@ -552,7 +596,7 @@ 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, LoadedBlock >::iterator i; 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++)
{ {
//Inaccurate - account for rest of loaded block. //Inaccurate - account for rest of loaded block.

View File

@ -32,7 +32,7 @@ using namespace PolyVox;
void TestVolume::testSize() void TestVolume::testSize()
{ {
const int32_t g_uVolumeSideLength = 128; const int32_t g_uVolumeSideLength = 128;
Volume<uint8_t> volData; Volume<uint8_t> volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength);
//Note: Deliberatly go past each edge by one to test if the bounds checking works. //Note: Deliberatly go past each edge by one to test if the bounds checking works.
for (int32_t z = 0; z < g_uVolumeSideLength + 1; z++) for (int32_t z = 0; z < g_uVolumeSideLength + 1; z++)