Moving Chunk to be a nested class of PagedVolume.
This commit is contained in:
		| @@ -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 | ||||
| @@ -76,10 +76,10 @@ namespace PolyVox | ||||
| 			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->getData() == false, "Chunk must have valid data"); | ||||
| 			POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data"); | ||||
|  | ||||
| 			std::stringstream ssFilename; | ||||
| 			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->getData() == false, "Chunk must have valid data"); | ||||
| 			POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data"); | ||||
|  | ||||
| 			POLYVOX_LOG_TRACE("Paging out data for " << region); | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,6 @@ freely, subject to the following restrictions: | ||||
| #include "PolyVoxCore/BaseVolume.h" | ||||
| #include "PolyVoxCore/Pager.h" | ||||
| #include "PolyVoxCore/Region.h" | ||||
| #include "PolyVoxCore/Chunk.h" | ||||
| #include "PolyVoxCore/Vector.h" | ||||
|  | ||||
| #include <limits> | ||||
| @@ -157,6 +156,46 @@ namespace PolyVox | ||||
| 	class PagedVolume : public BaseVolume<VoxelType> | ||||
| 	{ | ||||
| 	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 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 | ||||
| @@ -285,8 +324,8 @@ namespace PolyVox | ||||
|  | ||||
| 	private: | ||||
|  | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk<VoxelType> > > SharedPtrChunkMap; | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk<VoxelType> > > WeakPtrChunkMap; | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk > > SharedPtrChunkMap; | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk > > WeakPtrChunkMap; | ||||
|  | ||||
| 		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::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; | ||||
|  | ||||
| @@ -308,7 +347,7 @@ namespace PolyVox | ||||
|  | ||||
| 		mutable uint32_t m_uTimestamper; | ||||
| 		mutable Vector3DInt32 m_v3dLastAccessedChunkPos; | ||||
| 		mutable std::shared_ptr< Chunk<VoxelType> > m_pLastAccessedChunk; | ||||
| 		mutable std::shared_ptr<Chunk> m_pLastAccessedChunk; | ||||
| 		uint32_t m_uChunkCountLimit; | ||||
|  | ||||
| 		// The size of the volume | ||||
| @@ -328,6 +367,7 @@ namespace PolyVox | ||||
| } | ||||
|  | ||||
| #include "PolyVoxCore/PagedVolume.inl" | ||||
| #include "PolyVoxCore/PagedVolumeChunk.inl" | ||||
| #include "PolyVoxCore/PagedVolumeSampler.inl" | ||||
|  | ||||
| #endif //__PolyVox_PagedVolume_H__ | ||||
|   | ||||
| @@ -81,7 +81,7 @@ namespace PolyVox | ||||
| 		m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks); | ||||
| 		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) | ||||
| 			<< "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."); | ||||
|  | ||||
| 		// 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; | ||||
|  | ||||
| 		// 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> | ||||
| 	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); | ||||
|  | ||||
| @@ -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. | ||||
| 		std::shared_ptr< Chunk<VoxelType> > pChunk = nullptr; | ||||
| 		std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> pChunk = nullptr; | ||||
| 		typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos); | ||||
|  | ||||
| 		// Check whether the chunk was found. | ||||
| @@ -548,7 +548,7 @@ namespace PolyVox | ||||
| 				else | ||||
| 				{ | ||||
| 					// 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)); | ||||
| 				} | ||||
| 			} | ||||
| @@ -558,7 +558,7 @@ namespace PolyVox | ||||
| 		if (!pChunk) | ||||
| 		{ | ||||
| 			// 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. | ||||
| 			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 | ||||
| 		// 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> | ||||
|   | ||||
| @@ -26,7 +26,7 @@ freely, subject to the following restrictions: | ||||
| namespace PolyVox | ||||
| { | ||||
| 	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_bDataModified(true) | ||||
| 		,m_tData(0) | ||||
| @@ -65,7 +65,7 @@ namespace PolyVox | ||||
| 	} | ||||
| 
 | ||||
| 	template <typename VoxelType> | ||||
| 	Chunk<VoxelType>::~Chunk() | ||||
| 	PagedVolume<VoxelType>::Chunk::~Chunk() | ||||
| 	{ | ||||
| 		if (m_pPager && m_bDataModified) | ||||
| 		{ | ||||
| @@ -82,19 +82,19 @@ namespace PolyVox | ||||
| 	} | ||||
| 
 | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType* Chunk<VoxelType>::getData(void) const | ||||
| 	VoxelType* PagedVolume<VoxelType>::Chunk::getData(void) const | ||||
| 	{ | ||||
| 		return m_tData; | ||||
| 	} | ||||
| 
 | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| 	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  | ||||
| 		// 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> | ||||
| 	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()); | ||||
| 	} | ||||
| 
 | ||||
| 	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  | ||||
| 		// 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> | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
| 	template <typename VoxelType> | ||||
| 	uint32_t Chunk<VoxelType>::calculateSizeInBytes(void) | ||||
| 	uint32_t PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(void) | ||||
| 	{ | ||||
| 		// Call through to the static version | ||||
| 		return calculateSizeInBytes(m_uSideLength); | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 		// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier. | ||||
| @@ -24,7 +24,7 @@ freely, subject to the following restrictions: | ||||
| #ifndef __PolyVox_Pager_H__ | ||||
| #define __PolyVox_Pager_H__ | ||||
|  | ||||
| #include "PolyVoxCore/Chunk.h" | ||||
| #include "PolyVoxCore/PagedVolume.h" | ||||
| #include "PolyVoxCore/Impl/TypeDef.h" | ||||
|  | ||||
| #include <memory> | ||||
| @@ -43,8 +43,8 @@ namespace PolyVox | ||||
| 		/// Destructor | ||||
| 		virtual ~Pager() {}; | ||||
|  | ||||
| 		virtual void pageIn(const Region& region, Chunk<VoxelType>* pChunk) = 0; | ||||
| 		virtual void pageOut(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, typename PagedVolume<VoxelType>::Chunk* pChunk) = 0; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user