More renaming blocks to chunks.

This commit is contained in:
David Williams 2014-09-20 23:27:28 +02:00
parent 0ab7f27f0f
commit 71035029d1
6 changed files with 63 additions and 71 deletions

View File

@ -156,7 +156,6 @@ int main(int argc, char *argv[])
//createPerlinVolumeSlow(volData);
std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl;
//std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl;
//volData.setBlockCacheSize(64);
PolyVox::Region reg(Vector3DInt32(-255,0,0), Vector3DInt32(255,255,255));
std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl;
volData.prefetch(reg);

View File

@ -206,7 +206,7 @@ namespace PolyVox
///
/// \image html CubicSurfaceExtractor3.png
///
/// We could choose to add the quads to *both* regions, but this can cause confusion when one of the region is modified (causing the face to disappear or a new one to be created) as *both* regions need to have their mesh regenerated to correctly represent the new state of the volume data. Such pairs of coplanar quads can also cause problems with physics engines, and may prevent transparent block from rendering correctly. Therefore we choose to instead only add the quad to one of the the regions and we always choose the one with the greater coordinate value in the direction in which they differ. In the above example the regions differ by the 'x' component of their position, and so the quad is added to the region with the greater 'x' value (the one marked in blue).
/// We could choose to add the quads to *both* regions, but this can cause confusion when one of the region is modified (causing the face to disappear or a new one to be created) as *both* regions need to have their mesh regenerated to correctly represent the new state of the volume data. Such pairs of coplanar quads can also cause problems with physics engines, and may prevent transparent voxels from rendering correctly. Therefore we choose to instead only add the quad to one of the the regions and we always choose the one with the greater coordinate value in the direction in which they differ. In the above example the regions differ by the 'x' component of their position, and so the quad is added to the region with the greater 'x' value (the one marked in blue).
///
/// **Note:** *This behaviour has changed recently (September 2012). Earlier versions of PolyVox tried to be smart about this problem by looking beyond the region which was being processed, but this complicated the code and didn't work very well. Ultimatly we decided to simply stick with the convention outlined above.*
///

View File

@ -298,7 +298,7 @@ namespace PolyVox
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const;
std::shared_ptr< Chunk<VoxelType> > getChunk(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
std::shared_ptr< Chunk<VoxelType> > getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const;
void purgeNullPtrsFromAllChunks(void) const;
@ -309,10 +309,10 @@ namespace PolyVox
mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedChunkPos;
mutable std::shared_ptr< Chunk<VoxelType> > m_pLastAccessedChunk;
uint32_t m_uBlockCountLimit;
uint32_t m_uChunkCountLimit;
// The size of the volume
Region m_regValidRegionInBlocks;
Region m_regValidRegionInChunks;
// The size of the chunks
uint16_t m_uChunkSideLength;
@ -321,9 +321,9 @@ namespace PolyVox
Pager<VoxelType>* m_pPager;
// Enough to make sure a chunks and it's neighbours can be loaded, with a few to spare.
static const uint32_t uMinPracticalNoOfBlocks = 32;
static const uint32_t uMinPracticalNoOfChunks = 32;
// Should preent multi-gigabyte volumes with reasonable chunk sizes.
static const uint32_t uMaxPracticalNoOfBlocks = 32768;
static const uint32_t uMaxPracticalNoOfChunks = 32768;
};
}

View File

@ -54,7 +54,7 @@ namespace PolyVox
// expecting a high memory usage and will want a fair number of chunks to play around with.
if (regValid == Region::MaxRegion)
{
m_uBlockCountLimit = 1024;
m_uChunkCountLimit = 1024;
}
else
{
@ -67,23 +67,23 @@ namespace PolyVox
longestSide /= m_uChunkSideLength;
shortestSide /= m_uChunkSideLength;
m_uBlockCountLimit = longestSide * shortestSide;
m_uChunkCountLimit = longestSide * shortestSide;
}
}
else
{
// If there is no pager provided then we set the chunk limit to the maximum
// value to ensure the system never attempts to page chunks out of memory.
m_uBlockCountLimit = (std::numeric_limits<uint32_t>::max)();
m_uChunkCountLimit = (std::numeric_limits<uint32_t>::max)();
}
// Make sure the calculated chunk limit is within practical bounds
m_uBlockCountLimit = (std::max)(m_uBlockCountLimit, uMinPracticalNoOfBlocks);
m_uBlockCountLimit = (std::min)(m_uBlockCountLimit, uMaxPracticalNoOfBlocks);
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
uint32_t uChunkSizeInBytes = Chunk<VoxelType>::calculateSizeInBytes(m_uChunkSideLength);
POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uBlockCountLimit * uChunkSizeInBytes) / (1024 * 1024)
<< "Mb (" << m_uBlockCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024)
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
initialise();
}
@ -255,22 +255,22 @@ namespace PolyVox
// Calculate the number of chunks based on the memory limit and the size of each chunk.
uint32_t uChunkSizeInBytes = Chunk<VoxelType>::calculateSizeInBytes(m_uChunkSideLength);
m_uBlockCountLimit = uMemoryUsageInBytes / uChunkSizeInBytes;
m_uChunkCountLimit = uMemoryUsageInBytes / uChunkSizeInBytes;
// We need at least a few chunks available to avoid thrashing, and in pratice there will probably be hundreds.
POLYVOX_LOG_WARNING_IF(m_uBlockCountLimit < uMinPracticalNoOfBlocks, "Requested memory usage limit of "
POLYVOX_LOG_WARNING_IF(m_uChunkCountLimit < uMinPracticalNoOfChunks, "Requested memory usage limit of "
<< uMemoryUsageInBytes / (1024 * 1024) << "Mb is too low and cannot be adhered to.");
m_uBlockCountLimit = (std::max)(m_uBlockCountLimit, uMinPracticalNoOfBlocks);
m_uBlockCountLimit = (std::min)(m_uBlockCountLimit, uMaxPracticalNoOfBlocks);
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
// If the new limit is less than the number of chunks already loaded then the easiest solution is to flush and start loading again.
if (m_pRecentlyUsedChunks.size() > m_uBlockCountLimit)
if (m_pRecentlyUsedChunks.size() > m_uChunkCountLimit)
{
flushAll();
}
POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to " << (m_uBlockCountLimit * uChunkSizeInBytes) / (1024 * 1024)
<< "Mb (" << m_uBlockCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024)
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
}
////////////////////////////////////////////////////////////////////////////////
@ -364,7 +364,7 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
/// 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.
/// Note that if the memory usage limit 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.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
@ -385,9 +385,9 @@ namespace PolyVox
// Ensure we don't page in more chunks than the volume can hold.
Region region(v3dStart, v3dEnd);
uint32_t uNoOfBlocks = static_cast<uint32_t>(region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels());
POLYVOX_LOG_WARNING_IF(uNoOfBlocks > m_uBlockCountLimit, "Attempting to prefetch more than the maximum number of chunks.");
uNoOfBlocks = (std::min)(uNoOfBlocks, m_uBlockCountLimit);
uint32_t uNoOfChunks = static_cast<uint32_t>(region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels());
POLYVOX_LOG_WARNING_IF(uNoOfChunks > m_uChunkCountLimit, "Attempting to prefetch more than the maximum number of chunks.");
uNoOfChunks = (std::min)(uNoOfChunks, m_uChunkCountLimit);
// Loops over the specified positions and touch the corresponding chunks.
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
@ -420,7 +420,7 @@ namespace PolyVox
purgeNullPtrsFromAllChunks();
// If there are still some chunks left then this is a cause for concern. Perhaps samplers are holding on to them?
POLYVOX_LOG_WARNING_IF(m_pAllChunks.size() > 0, "Blocks still exist after performing flushAll()! Perhaps you have samplers attached?");
POLYVOX_LOG_WARNING_IF(m_pAllChunks.size() > 0, "Chunks still exist after performing flushAll()! Perhaps you have samplers attached?");
}
////////////////////////////////////////////////////////////////////////////////
@ -472,31 +472,29 @@ namespace PolyVox
//Validate parameters
if(m_uChunkSideLength == 0)
{
POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero.");
POLYVOX_THROW(std::invalid_argument, "Chunk side length cannot be zero.");
}
if(!isPowerOf2(m_uChunkSideLength))
{
POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two.");
POLYVOX_THROW(std::invalid_argument, "Chunk side length must be a power of two.");
}
m_uTimestamper = 0;
//m_uBlockCountLimit = 16;
//m_uMaxNumberOfBlocksInMemory = 1024;
m_v3dLastAccessedChunkPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedChunk pointer will be null;
m_pLastAccessedChunk = 0;
//Compute the chunk side length
m_uChunkSideLengthPower = logBase2(m_uChunkSideLength);
m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uChunkSideLengthPower);
m_regValidRegionInBlocks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uChunkSideLengthPower);
m_regValidRegionInBlocks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uChunkSideLengthPower);
m_regValidRegionInBlocks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uChunkSideLengthPower);
m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uChunkSideLengthPower);
m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uChunkSideLengthPower);
//setMaxNumberOfChunks(m_uBlockCountLimit);
//setMaxNumberOfChunks(m_uChunkCountLimit);
//Clear the previous data
m_pRecentlyUsedChunks.clear();
@ -508,22 +506,22 @@ namespace PolyVox
}
template <typename VoxelType>
std::shared_ptr< Chunk<VoxelType> > PagedVolume<VoxelType>::getChunk(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const
std::shared_ptr< Chunk<VoxelType> > PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const
{
Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ);
Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ);
//Check if we have the same chunk as last time, if so there's no need to even update
//the time stamp. If we updated it everytime then that would be every time we touched
//a voxel, which would overflow a uint32_t and require us to use a uint64_t instead.
//This check should also provide a significant speed boost as usually it is true.
if((v3dBlockPos == m_v3dLastAccessedChunkPos) && (m_pLastAccessedChunk != 0))
if((v3dChunkPos == m_v3dLastAccessedChunkPos) && (m_pLastAccessedChunk != 0))
{
return m_pLastAccessedChunk;
}
// The chunk was not the same as last time, but we can now hope it is in the set of most recently used chunks.
std::shared_ptr< Chunk<VoxelType> > pChunk = nullptr;
typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dBlockPos);
typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos);
// Check whether the chunk was found.
if ((itChunk) != m_pRecentlyUsedChunks.end())
@ -537,7 +535,7 @@ namespace PolyVox
{
// Although it's not in our recently use chunks, there's some (slim) chance that it
// exists in the list of all loaded chunks, because a sampler may be holding on to it.
typename WeakPtrChunkMap::iterator itWeakChunk = m_pAllChunks.find(v3dBlockPos);
typename WeakPtrChunkMap::iterator itWeakChunk = m_pAllChunks.find(v3dChunkPos);
if (itWeakChunk != m_pAllChunks.end())
{
// We've found an entry in the 'all chunks' list, but it can be null. This happens if a sampler was the
@ -551,7 +549,7 @@ namespace PolyVox
{
// The chunk is valid. We know it's not in the recently used list (we checked earlier) so it should be added.
pChunk = std::shared_ptr< Chunk<VoxelType> >(itWeakChunk->second);
m_pRecentlyUsedChunks.insert(std::make_pair(v3dBlockPos, pChunk));
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
}
}
}
@ -560,46 +558,46 @@ namespace PolyVox
if (!pChunk)
{
// The chunk was not found so we will create a new one.
pChunk = std::make_shared< Chunk<VoxelType> >(v3dBlockPos, m_uChunkSideLength, m_pPager);
pChunk = std::make_shared< Chunk<VoxelType> >(v3dChunkPos, m_uChunkSideLength, m_pPager);
// As we are loading a new chunk we should try to ensure we don't go over our target memory usage.
bool erasedBlock = false;
while (m_pRecentlyUsedChunks.size() + 1 > m_uBlockCountLimit) // +1 ready for new chunk we will add next.
bool erasedChunk = false;
while (m_pRecentlyUsedChunks.size() + 1 > m_uChunkCountLimit) // +1 ready for new chunk we will add next.
{
// This should never hit, because it should not have been possible for
// the user to limit the number of chunks if they did not provide a pager.
POLYVOX_ASSERT(m_pPager, "A valid pager is required to limit number of chunks");
// Find the least recently used chunk. Hopefully this isn't too slow.
typename SharedPtrChunkMap::iterator itUnloadBlock = m_pRecentlyUsedChunks.begin();
typename SharedPtrChunkMap::iterator itUnloadChunk = m_pRecentlyUsedChunks.begin();
for (typename SharedPtrChunkMap::iterator i = m_pRecentlyUsedChunks.begin(); i != m_pRecentlyUsedChunks.end(); i++)
{
if (i->second->m_uChunkLastAccessed < itUnloadBlock->second->m_uChunkLastAccessed)
if (i->second->m_uChunkLastAccessed < itUnloadChunk->second->m_uChunkLastAccessed)
{
itUnloadBlock = i;
itUnloadChunk = i;
}
}
// Erase the least recently used chunk
m_pRecentlyUsedChunks.erase(itUnloadBlock);
erasedBlock = true;
m_pRecentlyUsedChunks.erase(itUnloadChunk);
erasedChunk = true;
}
// If we've deleted any chunks from the recently used list then this
// seems like a good place to purge the 'all chunks' list as well.
if (erasedBlock)
if (erasedChunk)
{
purgeNullPtrsFromAllChunks();
}
// Add our new chunk to the maps.
m_pAllChunks.insert(std::make_pair(v3dBlockPos, pChunk));
m_pRecentlyUsedChunks.insert(std::make_pair(v3dBlockPos, pChunk));
m_pAllChunks.insert(std::make_pair(v3dChunkPos, pChunk));
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
}
pChunk->m_uChunkLastAccessed = ++m_uTimestamper;
m_pLastAccessedChunk = pChunk;
m_v3dLastAccessedChunkPos = v3dBlockPos;
m_v3dLastAccessedChunkPos = v3dChunkPos;
return pChunk;
}

View File

@ -107,21 +107,21 @@ namespace PolyVox
// Then we update the voxel pointer
if(this->isCurrentPositionValid())
{
const int32_t uXBlock = this->mXPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uYBlock = this->mYPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uZBlock = this->mZPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uXChunk = this->mXPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uYChunk = this->mYPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uZChunk = this->mZPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const uint16_t uXPosInBlock = static_cast<uint16_t>(this->mXPosInVolume - (uXBlock << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uYPosInBlock = static_cast<uint16_t>(this->mYPosInVolume - (uYBlock << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uZPosInBlock = static_cast<uint16_t>(this->mZPosInVolume - (uZBlock << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uXPosInChunk = static_cast<uint16_t>(this->mXPosInVolume - (uXChunk << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uYPosInChunk = static_cast<uint16_t>(this->mYPosInVolume - (uYChunk << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uZPosInChunk = static_cast<uint16_t>(this->mZPosInVolume - (uZChunk << this->mVolume->m_uChunkSideLengthPower));
const uint32_t uVoxelIndexInBlock = uXPosInBlock +
uYPosInBlock * this->mVolume->m_uChunkSideLength +
uZPosInBlock * this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
const uint32_t uVoxelIndexInChunk = uXPosInChunk +
uYPosInChunk * this->mVolume->m_uChunkSideLength +
uZPosInChunk * this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
auto pUncompressedCurrentBlock = this->mVolume->getChunk(uXBlock, uYBlock, uZBlock);
auto pCurrentChunk = this->mVolume->getChunk(uXChunk, uYChunk, uZChunk);
mCurrentVoxel = pUncompressedCurrentBlock->m_tData + uVoxelIndexInBlock;
mCurrentVoxel = pCurrentChunk->m_tData + uVoxelIndexInChunk;
}
else
{

View File

@ -62,11 +62,6 @@ namespace PolyVox
typedef Array<3,int32_t> Array3DInt32;
typedef Array<3,uint32_t> Array3DUint32;*/
////////////////////////////////////////////////////////////////////////////////
// BlockCompressor
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class BlockCompressor;
////////////////////////////////////////////////////////////////////////////////
// Compressor
////////////////////////////////////////////////////////////////////////////////