Removing explicit functions to control the number of compressed and uncompressed blocks in memory, and letting the user set a memory limit instead.

This commit is contained in:
Daviw Williams 2013-07-04 16:23:58 +02:00
parent 26f512eba7
commit bd60f34bd7
5 changed files with 61 additions and 30 deletions

View File

@ -153,8 +153,9 @@ int main(int argc, char *argv[])
RLECompressor<MaterialDensityPair44, uint16_t>* compressor = new RLECompressor<MaterialDensityPair44, uint16_t>(); RLECompressor<MaterialDensityPair44, uint16_t>* compressor = new RLECompressor<MaterialDensityPair44, uint16_t>();
PerlinNoisePager* pager = new PerlinNoisePager(); PerlinNoisePager* pager = new PerlinNoisePager();
LargeVolume<MaterialDensityPair44> volData(PolyVox::Region::MaxRegion, compressor, pager, 256); LargeVolume<MaterialDensityPair44> volData(PolyVox::Region::MaxRegion, compressor, pager, 256);
volData.setMaxNumberOfBlocksInMemory(4096); //volData.setMaxNumberOfBlocksInMemory(4096);
volData.setMaxNumberOfUncompressedBlocks(64); //volData.setMaxNumberOfUncompressedBlocks(64);
volData.setTargetMemoryLimitInBytes(128 * 1024 * 1024);
//volData.setMaxNumberOfUncompressedBlocks(4096); //volData.setMaxNumberOfUncompressedBlocks(4096);
//createSphereInVolume(volData, 30); //createSphereInVolume(volData, 30);

View File

@ -269,8 +269,9 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
uint32_t Block<VoxelType>::calculateSizeInBytes(void) uint32_t Block<VoxelType>::calculateSizeInBytes(void)
{ {
//FIXME - This function is incomplete. // Returns the size of this class plus the size of the compressed data. It
uint32_t uSizeInBytes = sizeof(Block<VoxelType>); // doesn't include the uncompressed data cache as that is owned by the volume.
uint32_t uSizeInBytes = sizeof(Block<VoxelType>) + m_uCompressedDataLength;
return uSizeInBytes; return uSizeInBytes;
} }
} }

View File

@ -263,10 +263,10 @@ namespace PolyVox
/// Gets a voxel at the position given by a 3D vector /// Gets a voxel at the position given by a 3D vector
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
void setTargetMemoryLimitInBytes(uint32_t uTargetMemoryLimitInBytes);
/// Sets the number of blocks for which uncompressed data is stored /// Sets the number of blocks for which uncompressed data is stored
void setMaxNumberOfUncompressedBlocks(uint32_t uMaxNumberOfUncompressedBlocks); void setMaxNumberOfUncompressedBlocks(uint32_t uMaxNumberOfUncompressedBlocks);
/// Sets the number of blocks which can be in memory before the paging system starts unloading them
void setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates /// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
/// Sets the voxel at the position given by a 3D vector /// Sets the voxel at the position given by a 3D vector
@ -315,6 +315,8 @@ namespace PolyVox
}; };
void initialise(); void initialise();
uint32_t calculateBlockMemoryUsage(void) const;
// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 // A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057
template <WrapMode eWrapMode> template <WrapMode eWrapMode>
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const; VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const;
@ -338,7 +340,8 @@ namespace PolyVox
mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable Block<VoxelType>* m_pLastAccessedBlock; mutable Block<VoxelType>* m_pLastAccessedBlock;
uint32_t m_uMaxNumberOfUncompressedBlocks; uint32_t m_uMaxNumberOfUncompressedBlocks;
uint32_t m_uMaxNumberOfBlocksInMemory;
uint32_t m_uCompressedBlockMemoryLimitInBytes;
// The size of the volume // The size of the volume
Region m_regValidRegionInBlocks; Region m_regValidRegionInBlocks;

View File

@ -25,6 +25,8 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/MinizCompressor.h" #include "PolyVoxCore/MinizCompressor.h"
#include <algorithm>
namespace PolyVox namespace PolyVox
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -241,6 +243,25 @@ namespace PolyVox
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
} }
template <typename VoxelType>
void LargeVolume<VoxelType>::setTargetMemoryLimitInBytes(uint32_t uTargetMemoryLimitInBytes)
{
uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
uint32_t uIdealNoOfUncompressedBlocks = m_regValidRegionInBlocks.getWidthInVoxels() + m_regValidRegionInBlocks.getHeightInVoxels() * m_regValidRegionInBlocks.getDepthInVoxels();
// Let's say that we should never use more than half the available memory for the uncompressed block cache.
uint32_t uMaxMemoryForUncompressedBlocks = uTargetMemoryLimitInBytes / 2;
uint32_t uMaxFittableNoOfUncompressedBlocks = uMaxMemoryForUncompressedBlocks / uUncompressedBlockSizeInBytes;
setMaxNumberOfUncompressedBlocks((std::min)(uIdealNoOfUncompressedBlocks, uMaxFittableNoOfUncompressedBlocks));
uint32_t uUncompressedBlockCacheSizeInBytes = m_uMaxNumberOfUncompressedBlocks * uUncompressedBlockSizeInBytes;
m_uCompressedBlockMemoryLimitInBytes = uTargetMemoryLimitInBytes - uUncompressedBlockCacheSizeInBytes;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Increasing the size of the block cache will increase memory but may improve performance. /// Increasing the size of the block cache will increase memory but may improve performance.
/// You may want to set this to a large value (e.g. 1024) when you are first loading your /// You may want to set this to a large value (e.g. 1024) when you are first loading your
@ -255,20 +276,6 @@ namespace PolyVox
m_uMaxNumberOfUncompressedBlocks = uMaxNumberOfUncompressedBlocks; m_uMaxNumberOfUncompressedBlocks = uMaxNumberOfUncompressedBlocks;
} }
////////////////////////////////////////////////////////////////////////////////
/// Increasing the number of blocks in memory causes fewer calls to dataRequiredHandler()/dataOverflowHandler()
/// \param uMaxNumberOfBlocksInMemory The number of blocks
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void LargeVolume<VoxelType>::setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory)
{
if(m_pBlocks.size() > uMaxNumberOfBlocksInMemory)
{
flushAll();
}
m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel /// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel /// \param uYPos the \c y position of the voxel
@ -361,7 +368,7 @@ namespace PolyVox
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Note that if MaxNumberOfBlocksInMemory is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels. /// Note that if *NOTE - update docs - MaxNumberOfBlocksInMemory no longer exists* MaxNumberOfBlocksInMemory is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels.
/// \param regPrefetch The Region of voxels to prefetch into memory. /// \param regPrefetch The Region of voxels to prefetch into memory.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
@ -381,11 +388,14 @@ namespace PolyVox
Vector3DInt32 v3dSize = v3dEnd - v3dStart + Vector3DInt32(1,1,1); Vector3DInt32 v3dSize = v3dEnd - v3dStart + Vector3DInt32(1,1,1);
uint32_t numblocks = static_cast<uint32_t>(v3dSize.getX() * v3dSize.getY() * v3dSize.getZ()); uint32_t numblocks = static_cast<uint32_t>(v3dSize.getX() * v3dSize.getY() * v3dSize.getZ());
if(numblocks > m_uMaxNumberOfBlocksInMemory)
// FIXME - reinstate some logic to handle when the prefetched region is too large.
/*if(numblocks > m_uMaxNumberOfBlocksInMemory)
{ {
// cannot support the amount of blocks... so only load the maximum possible // cannot support the amount of blocks... so only load the maximum possible
numblocks = m_uMaxNumberOfBlocksInMemory; numblocks = m_uMaxNumberOfBlocksInMemory;
} }*/
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++) for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
{ {
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++) for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
@ -511,8 +521,8 @@ namespace PolyVox
} }
m_uTimestamper = 0; m_uTimestamper = 0;
m_uMaxNumberOfUncompressedBlocks = 16; //m_uMaxNumberOfUncompressedBlocks = 16;
m_uMaxNumberOfBlocksInMemory = 1024; //m_uMaxNumberOfBlocksInMemory = 1024;
m_v3dLastAccessedBlockPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedBlock pointer will be null; m_v3dLastAccessedBlockPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedBlock pointer will be null;
m_pLastAccessedBlock = 0; m_pLastAccessedBlock = 0;
@ -526,7 +536,7 @@ namespace PolyVox
m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower); m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower); m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower);
setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks); //setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks);
//Clear the previous data //Clear the previous data
m_pBlocks.clear(); m_pBlocks.clear();
@ -600,7 +610,7 @@ namespace PolyVox
if(m_pPager) if(m_pPager)
{ {
// check wether another block needs to be unloaded before this one can be loaded // check wether another block needs to be unloaded before this one can be loaded
if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory) while(calculateBlockMemoryUsage() > m_uCompressedBlockMemoryLimitInBytes) //FIXME - This calculation of size is slow and should be outside the loop.
{ {
// find the least recently used block // find the least recently used block
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i; typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i;
@ -721,6 +731,21 @@ namespace PolyVox
return uSizeInBytes; return uSizeInBytes;
} }
template <typename VoxelType>
uint32_t LargeVolume<VoxelType>::calculateBlockMemoryUsage(void) const
{
uint32_t uMemoryUsage = 0;
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
//Inaccurate - account for rest of loaded block.
uMemoryUsage += i->second.calculateSizeInBytes();
}
return uMemoryUsage;
}
template <typename VoxelType> template <typename VoxelType>
template <WrapMode eWrapMode> template <WrapMode eWrapMode>
VoxelType LargeVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const VoxelType LargeVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const

View File

@ -281,8 +281,9 @@ TestVolume::TestVolume()
m_pSimpleVolume = new SimpleVolume<int32_t>(region); m_pSimpleVolume = new SimpleVolume<int32_t>(region);
m_pLargeVolume = new LargeVolume<int32_t>(region, m_pCompressor, m_pFilePager, 32); m_pLargeVolume = new LargeVolume<int32_t>(region, m_pCompressor, m_pFilePager, 32);
m_pLargeVolume->setMaxNumberOfBlocksInMemory(32); //m_pLargeVolume->setMaxNumberOfBlocksInMemory(32);
m_pLargeVolume->setMaxNumberOfUncompressedBlocks(16); //m_pLargeVolume->setMaxNumberOfUncompressedBlocks(16);
m_pLargeVolume->setTargetMemoryLimitInBytes(4 * 1024 * 1024);
//Fill the volume with some data //Fill the volume with some data
for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++)