|  |  |  | @@ -51,8 +51,25 @@ namespace PolyVox | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (m_pPager) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			// If a pager is available then we can set a sensible limit on our memory usage. | 
		
	
		
			
				|  |  |  |  | 			m_uBlockCountLimit = 256; | 
		
	
		
			
				|  |  |  |  | 			// If the user is creating a vast (almost infinite) volume then we can bet they will be | 
		
	
		
			
				|  |  |  |  | 			// expecting a high memory usage and will want a fair number of blocks to play around with. | 
		
	
		
			
				|  |  |  |  | 			if (regValid == Region::MaxRegion) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				m_uBlockCountLimit = 1024; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			else | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				// Otherwise we try to choose a block count to avoid too much thrashing, particularly when iterating | 
		
	
		
			
				|  |  |  |  | 				// over the whole volume. This means at least enough blocks to cover one edge of the volume, and ideally  | 
		
	
		
			
				|  |  |  |  | 				// enough for a whole face. Which face? Longest edge by shortest edge seems like a reasonable guess. | 
		
	
		
			
				|  |  |  |  | 				uint32_t longestSide = (std::max)(regValid.getWidthInVoxels(), (std::max)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels())); | 
		
	
		
			
				|  |  |  |  | 				uint32_t shortestSide = (std::min)(regValid.getWidthInVoxels(), (std::min)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels())); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				longestSide /= m_uBlockSideLength; | 
		
	
		
			
				|  |  |  |  | 				shortestSide /= m_uBlockSideLength; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				m_uBlockCountLimit = longestSide * shortestSide; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -61,6 +78,14 @@ namespace PolyVox | 
		
	
		
			
				|  |  |  |  | 			m_uBlockCountLimit = (std::numeric_limits<uint32_t>::max)(); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// Make sure the calculated block limit is within practical bounds | 
		
	
		
			
				|  |  |  |  | 		m_uBlockCountLimit = (std::max)(m_uBlockCountLimit, uMinPracticalNoOfBlocks); | 
		
	
		
			
				|  |  |  |  | 		m_uBlockCountLimit = (std::min)(m_uBlockCountLimit, uMaxPracticalNoOfBlocks); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		uint32_t uUncompressedBlockSizeInBytes = UncompressedBlock<VoxelType>::calculateSizeInBytes(m_uBlockSideLength); | 
		
	
		
			
				|  |  |  |  | 		POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uBlockCountLimit * uUncompressedBlockSizeInBytes) / (1024 * 1024) | 
		
	
		
			
				|  |  |  |  | 			<< "Mb (" << m_uBlockCountLimit << " blocks of " << uUncompressedBlockSizeInBytes / 1024 << "Kb each)."); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		initialise(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -229,22 +254,24 @@ 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."); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// Calculate the number of blocks based on the memory limit and the size of each block. | 
		
	
		
			
				|  |  |  |  | 		uint32_t uUncompressedBlockSizeInBytes = UncompressedBlock<VoxelType>::calculateSizeInBytes(m_uBlockSideLength); | 
		
	
		
			
				|  |  |  |  | 		m_uBlockCountLimit = uMemoryUsageInBytes / uUncompressedBlockSizeInBytes; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		const uint32_t uMinPracticalNoOfBlocks = 4; | 
		
	
		
			
				|  |  |  |  | 		POLYVOX_LOG_WARNING_IF(m_uBlockCountLimit < uMinPracticalNoOfBlocks, "The memory usage limit is set too low and cannot be adhered to."); | 
		
	
		
			
				|  |  |  |  | 		// We need at least a few blocks available to avoid thrashing, and in pratice there will probably be hundreds. | 
		
	
		
			
				|  |  |  |  | 		POLYVOX_LOG_WARNING_IF(m_uBlockCountLimit < uMinPracticalNoOfBlocks, "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); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// If the new limit is less than the number of blocks already loaded then the easiest solution is to flush and start loading again. | 
		
	
		
			
				|  |  |  |  | 		if (m_pRecentlyUsedBlocks.size() > m_uBlockCountLimit) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			flushAll(); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		POLYVOX_LOG_DEBUG("Target memory usage for volume set to " << uMemoryUsageInBytes << "bytes (" | 
		
	
		
			
				|  |  |  |  | 			<< m_uBlockCountLimit << " blocks of " << uUncompressedBlockSizeInBytes << "bytes each)."); | 
		
	
		
			
				|  |  |  |  | 		POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to " << (m_uBlockCountLimit * uUncompressedBlockSizeInBytes) / (1024 * 1024) | 
		
	
		
			
				|  |  |  |  | 			<< "Mb (" << m_uBlockCountLimit << " blocks of " << uUncompressedBlockSizeInBytes / 1024 << "Kb each)."); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	//////////////////////////////////////////////////////////////////////////////// | 
		
	
	
		
			
				
					
					|  |  |  | @@ -579,24 +606,19 @@ namespace PolyVox | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	//////////////////////////////////////////////////////////////////////////////// | 
		
	
		
			
				|  |  |  |  | 	/// Note: This function needs reviewing for accuracy... | 
		
	
		
			
				|  |  |  |  | 	/// Calculate the memory usage of the volume. | 
		
	
		
			
				|  |  |  |  | 	//////////////////////////////////////////////////////////////////////////////// | 
		
	
		
			
				|  |  |  |  | 	template <typename VoxelType> | 
		
	
		
			
				|  |  |  |  | 	uint32_t LargeVolume<VoxelType>::calculateSizeInBytes(void) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Purge null blocks so we know that all blocks are used. | 
		
	
		
			
				|  |  |  |  | 		purgeNullPtrsFromAllBlocks(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// We include the size of the LargeVolume class but it should be insignificant. | 
		
	
		
			
				|  |  |  |  | 		uint32_t uSizeInBytes = sizeof(LargeVolume); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		//Memory used by the blocks | 
		
	
		
			
				|  |  |  |  | 		typename SharedPtrBlockMap::iterator i; | 
		
	
		
			
				|  |  |  |  | 		for (i = m_pRecentlyUsedBlocks.begin(); i != m_pRecentlyUsedBlocks.end(); i++) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			//Inaccurate - account for rest of loaded block. | 
		
	
		
			
				|  |  |  |  | 			uSizeInBytes += i->second->calculateSizeInBytes(); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		//Memory used by the block cache. | 
		
	
		
			
				|  |  |  |  | 		//uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(Block<VoxelType>); | 
		
	
		
			
				|  |  |  |  | 		//uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); | 
		
	
		
			
				|  |  |  |  | 		// Memory used by the blocks | 
		
	
		
			
				|  |  |  |  | 		uSizeInBytes += UncompressedBlock<VoxelType>::calculateSizeInBytes(m_uBlockSideLength) * m_pAllBlocks.size(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		return uSizeInBytes; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
	
		
			
				
					
					|  |  |  |   |