Moving Chunk to be a nested class of PagedVolume.

This commit is contained in:
David Williams 2014-09-21 10:27:55 +02:00
parent 71035029d1
commit db9a74fdb4
8 changed files with 72 additions and 110 deletions

View File

@ -90,7 +90,7 @@ public:
/// Destructor /// Destructor
virtual ~PerlinNoisePager() {}; virtual ~PerlinNoisePager() {};
virtual void pageIn(const PolyVox::Region& region, Chunk<MaterialDensityPair44>* pChunk) virtual void pageIn(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* pChunk)
{ {
Perlin perlin(2,2,1,234); Perlin perlin(2,2,1,234);
@ -134,7 +134,7 @@ public:
} }
} }
virtual void pageOut(const PolyVox::Region& region, Chunk<MaterialDensityPair44>* /*pChunk*/) virtual void pageOut(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* /*pChunk*/)
{ {
std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl;
} }

View File

@ -38,8 +38,6 @@ SET(CORE_INC_FILES
include/PolyVoxCore/BaseVolume.h include/PolyVoxCore/BaseVolume.h
include/PolyVoxCore/BaseVolume.inl include/PolyVoxCore/BaseVolume.inl
include/PolyVoxCore/BaseVolumeSampler.inl include/PolyVoxCore/BaseVolumeSampler.inl
include/PolyVoxCore/Chunk.h
include/PolyVoxCore/Chunk.inl
include/PolyVoxCore/CubicSurfaceExtractor.h include/PolyVoxCore/CubicSurfaceExtractor.h
include/PolyVoxCore/CubicSurfaceExtractor.inl include/PolyVoxCore/CubicSurfaceExtractor.inl
include/PolyVoxCore/DefaultIsQuadNeeded.h include/PolyVoxCore/DefaultIsQuadNeeded.h
@ -62,6 +60,7 @@ SET(CORE_INC_FILES
include/PolyVoxCore/Mesh.inl include/PolyVoxCore/Mesh.inl
include/PolyVoxCore/PagedVolume.h include/PolyVoxCore/PagedVolume.h
include/PolyVoxCore/PagedVolume.inl include/PolyVoxCore/PagedVolume.inl
include/PolyVoxCore/PagedVolumeChunk.inl
include/PolyVoxCore/PagedVolumeSampler.inl include/PolyVoxCore/PagedVolumeSampler.inl
include/PolyVoxCore/Pager.h include/PolyVoxCore/Pager.h
include/PolyVoxCore/PolyVoxForwardDeclarations.h include/PolyVoxCore/PolyVoxForwardDeclarations.h

View File

@ -1,77 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_Chunk_H__
#define __PolyVox_Chunk_H__
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
#include "PolyVoxCore/Vector.h"
namespace PolyVox
{
template <typename VoxelType>
class Chunk
{
friend class PagedVolume<VoxelType>;
public:
Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager<VoxelType>* pPager = nullptr);
~Chunk();
VoxelType* getData(void) const;
uint32_t getDataSizeInBytes(void) const;
VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
VoxelType getVoxel(const Vector3DUint16& v3dPos) const;
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
private:
/// Private copy constructor to prevent accisdental copying
Chunk(const Chunk& /*rhs*/) {};
/// Private assignment operator to prevent accisdental copying
Chunk& operator=(const Chunk& /*rhs*/) {};
// This is updated by the PagedVolume and used to discard the least recently used chunks.
uint32_t m_uChunkLastAccessed;
// This is so we can tell whether a uncompressed chunk has to be recompressed and whether
// a compressed chunk has to be paged back to disk, or whether they can just be discarded.
bool m_bDataModified;
uint32_t calculateSizeInBytes(void);
static uint32_t calculateSizeInBytes(uint32_t uSideLength);
VoxelType* m_tData;
uint16_t m_uSideLength;
uint8_t m_uSideLengthPower;
Pager<VoxelType>* m_pPager;
Vector3DInt32 m_v3dChunkSpacePosition;
};
}
#include "PolyVoxCore/Chunk.inl"
#endif

View File

@ -76,10 +76,10 @@ namespace PolyVox
m_vecCreatedFiles.clear(); m_vecCreatedFiles.clear();
} }
virtual void pageIn(const Region& region, Chunk<VoxelType>* pChunk) virtual void pageIn(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk)
{ {
POLYVOX_ASSERT(pChunk, "Attempting to page in NULL chunk"); POLYVOX_ASSERT(pChunk, "Attempting to page in NULL chunk");
POLYVOX_ASSERT(pChunk->getData() == false, "Chunk must have valid data"); POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
std::stringstream ssFilename; std::stringstream ssFilename;
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-" ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-"
@ -120,10 +120,10 @@ namespace PolyVox
} }
} }
virtual void pageOut(const Region& region, Chunk<VoxelType>* pChunk) virtual void pageOut(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk)
{ {
POLYVOX_ASSERT(pChunk, "Attempting to page out NULL chunk"); POLYVOX_ASSERT(pChunk, "Attempting to page out NULL chunk");
POLYVOX_ASSERT(pChunk->getData() == false, "Chunk must have valid data"); POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
POLYVOX_LOG_TRACE("Paging out data for " << region); POLYVOX_LOG_TRACE("Paging out data for " << region);

View File

@ -27,7 +27,6 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/BaseVolume.h" #include "PolyVoxCore/BaseVolume.h"
#include "PolyVoxCore/Pager.h" #include "PolyVoxCore/Pager.h"
#include "PolyVoxCore/Region.h" #include "PolyVoxCore/Region.h"
#include "PolyVoxCore/Chunk.h"
#include "PolyVoxCore/Vector.h" #include "PolyVoxCore/Vector.h"
#include <limits> #include <limits>
@ -157,6 +156,46 @@ namespace PolyVox
class PagedVolume : public BaseVolume<VoxelType> class PagedVolume : public BaseVolume<VoxelType>
{ {
public: public:
class Chunk
{
public:
Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager<VoxelType>* pPager = nullptr);
~Chunk();
VoxelType* getData(void) const;
uint32_t getDataSizeInBytes(void) const;
VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
VoxelType getVoxel(const Vector3DUint16& v3dPos) const;
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
public:
/// Private copy constructor to prevent accisdental copying
Chunk(const Chunk& /*rhs*/) {};
/// Private assignment operator to prevent accisdental copying
Chunk& operator=(const Chunk& /*rhs*/) {};
// This is updated by the PagedVolume and used to discard the least recently used chunks.
uint32_t m_uChunkLastAccessed;
// This is so we can tell whether a uncompressed chunk has to be recompressed and whether
// a compressed chunk has to be paged back to disk, or whether they can just be discarded.
bool m_bDataModified;
uint32_t calculateSizeInBytes(void);
static uint32_t calculateSizeInBytes(uint32_t uSideLength);
VoxelType* m_tData;
uint16_t m_uSideLength;
uint8_t m_uSideLengthPower;
Pager<VoxelType>* m_pPager;
Vector3DInt32 m_v3dChunkSpacePosition;
};
//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared. //There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared.
//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but //There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but
//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler //which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler
@ -285,8 +324,8 @@ namespace PolyVox
private: private:
typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk<VoxelType> > > SharedPtrChunkMap; typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk > > SharedPtrChunkMap;
typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk<VoxelType> > > WeakPtrChunkMap; typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk > > WeakPtrChunkMap;
void initialise(); void initialise();
@ -298,7 +337,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::Border>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, 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 uChunkX, int32_t uChunkY, int32_t uChunkZ) const; std::shared_ptr<Chunk> getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const;
void purgeNullPtrsFromAllChunks(void) const; void purgeNullPtrsFromAllChunks(void) const;
@ -308,7 +347,7 @@ namespace PolyVox
mutable uint32_t m_uTimestamper; mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedChunkPos; mutable Vector3DInt32 m_v3dLastAccessedChunkPos;
mutable std::shared_ptr< Chunk<VoxelType> > m_pLastAccessedChunk; mutable std::shared_ptr<Chunk> m_pLastAccessedChunk;
uint32_t m_uChunkCountLimit; uint32_t m_uChunkCountLimit;
// The size of the volume // The size of the volume
@ -328,6 +367,7 @@ namespace PolyVox
} }
#include "PolyVoxCore/PagedVolume.inl" #include "PolyVoxCore/PagedVolume.inl"
#include "PolyVoxCore/PagedVolumeChunk.inl"
#include "PolyVoxCore/PagedVolumeSampler.inl" #include "PolyVoxCore/PagedVolumeSampler.inl"
#endif //__PolyVox_PagedVolume_H__ #endif //__PolyVox_PagedVolume_H__

View File

@ -81,7 +81,7 @@ namespace PolyVox
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks); m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks); m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
uint32_t uChunkSizeInBytes = Chunk<VoxelType>::calculateSizeInBytes(m_uChunkSideLength); uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024) 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)."); << "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
@ -254,7 +254,7 @@ namespace PolyVox
POLYVOX_THROW_IF(!m_pPager, invalid_operation, "You cannot limit the memory usage of the volume because it was created without a pager attached."); POLYVOX_THROW_IF(!m_pPager, invalid_operation, "You cannot limit the memory usage of the volume because it was created without a pager attached.");
// Calculate the number of chunks based on the memory limit and the size of each chunk. // Calculate the number of chunks based on the memory limit and the size of each chunk.
uint32_t uChunkSizeInBytes = Chunk<VoxelType>::calculateSizeInBytes(m_uChunkSideLength); uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
m_uChunkCountLimit = 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. // We need at least a few chunks available to avoid thrashing, and in pratice there will probably be hundreds.
@ -506,7 +506,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
std::shared_ptr< Chunk<VoxelType> > PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const
{ {
Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ); Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ);
@ -520,7 +520,7 @@ namespace PolyVox
} }
// The chunk was not the same as last time, but we can now hope it is in the set of most recently used chunks. // 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; std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> pChunk = nullptr;
typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos); typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos);
// Check whether the chunk was found. // Check whether the chunk was found.
@ -548,7 +548,7 @@ namespace PolyVox
else else
{ {
// The chunk is valid. We know it's not in the recently used list (we checked earlier) so it should be added. // 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); pChunk = std::shared_ptr< PagedVolume<VoxelType>::Chunk >(itWeakChunk->second);
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk)); m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
} }
} }
@ -558,7 +558,7 @@ namespace PolyVox
if (!pChunk) if (!pChunk)
{ {
// The chunk was not found so we will create a new one. // The chunk was not found so we will create a new one.
pChunk = std::make_shared< Chunk<VoxelType> >(v3dChunkPos, m_uChunkSideLength, m_pPager); pChunk = std::make_shared< PagedVolume<VoxelType>::Chunk >(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. // As we are loading a new chunk we should try to ensure we don't go over our target memory usage.
bool erasedChunk = false; bool erasedChunk = false;
@ -613,7 +613,7 @@ namespace PolyVox
// Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the // Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the
// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier. // allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier.
return Chunk<VoxelType>::calculateSizeInBytes(m_uChunkSideLength) * m_pAllChunks.size(); return PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength) * m_pAllChunks.size();
} }
template <typename VoxelType> template <typename VoxelType>

View File

@ -26,7 +26,7 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
template <typename VoxelType> template <typename VoxelType>
Chunk<VoxelType>::Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager<VoxelType>* pPager) PagedVolume<VoxelType>::Chunk::Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager<VoxelType>* pPager)
:m_uChunkLastAccessed(0) :m_uChunkLastAccessed(0)
,m_bDataModified(true) ,m_bDataModified(true)
,m_tData(0) ,m_tData(0)
@ -65,7 +65,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
Chunk<VoxelType>::~Chunk() PagedVolume<VoxelType>::Chunk::~Chunk()
{ {
if (m_pPager && m_bDataModified) if (m_pPager && m_bDataModified)
{ {
@ -82,19 +82,19 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType* Chunk<VoxelType>::getData(void) const VoxelType* PagedVolume<VoxelType>::Chunk::getData(void) const
{ {
return m_tData; return m_tData;
} }
template <typename VoxelType> template <typename VoxelType>
uint32_t Chunk<VoxelType>::getDataSizeInBytes(void) const uint32_t PagedVolume<VoxelType>::Chunk::getDataSizeInBytes(void) const
{ {
return m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType); return m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType Chunk<VoxelType>::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{ {
// This code is not usually expected to be called by the user, with the exception of when implementing paging // This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions. // of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
@ -112,13 +112,13 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType Chunk<VoxelType>::getVoxel(const Vector3DUint16& v3dPos) const VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(const Vector3DUint16& v3dPos) const
{ {
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
} }
template <typename VoxelType> template <typename VoxelType>
void Chunk<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) void PagedVolume<VoxelType>::Chunk::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{ {
// This code is not usually expected to be called by the user, with the exception of when implementing paging // This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions. // of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
@ -138,20 +138,20 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
void Chunk<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) void PagedVolume<VoxelType>::Chunk::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
{ {
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
} }
template <typename VoxelType> template <typename VoxelType>
uint32_t Chunk<VoxelType>::calculateSizeInBytes(void) uint32_t PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(void)
{ {
// Call through to the static version // Call through to the static version
return calculateSizeInBytes(m_uSideLength); return calculateSizeInBytes(m_uSideLength);
} }
template <typename VoxelType> template <typename VoxelType>
uint32_t Chunk<VoxelType>::calculateSizeInBytes(uint32_t uSideLength) uint32_t PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(uint32_t uSideLength)
{ {
// Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the // Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the
// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier. // allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier.

View File

@ -24,7 +24,7 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_Pager_H__ #ifndef __PolyVox_Pager_H__
#define __PolyVox_Pager_H__ #define __PolyVox_Pager_H__
#include "PolyVoxCore/Chunk.h" #include "PolyVoxCore/PagedVolume.h"
#include "PolyVoxCore/Impl/TypeDef.h" #include "PolyVoxCore/Impl/TypeDef.h"
#include <memory> #include <memory>
@ -43,8 +43,8 @@ namespace PolyVox
/// Destructor /// Destructor
virtual ~Pager() {}; virtual ~Pager() {};
virtual void pageIn(const Region& region, Chunk<VoxelType>* pChunk) = 0; virtual void pageIn(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk) = 0;
virtual void pageOut(const Region& region, Chunk<VoxelType>* pChunk) = 0; virtual void pageOut(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk) = 0;
}; };
} }