Index: library/PolyVoxCore/include/Volume.inl =================================================================== --- library/PolyVoxCore/include/Volume.inl (revision 1429) +++ library/PolyVoxCore/include/Volume.inl (working copy) @@ -129,10 +129,7 @@ template Volume::~Volume() { - typename std::map::iterator i; - for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i = m_pBlocks.begin()) { - eraseBlock(i); - } + flushAll(); } //////////////////////////////////////////////////////////////////////////////// @@ -302,25 +299,9 @@ template void Volume::setMaxNumberOfBlocksInMemory(uint16_t uMaxNumberOfBlocksInMemory) { - //FIXME? - I'm concerned about the logic in here... particularly the - //way timestamps are handled. Perhaps extract all timestamps, sort them, - //identify the cut-off point, and then discard those above it? if(m_pBlocks.size() > uMaxNumberOfBlocksInMemory) { - // we need to unload some blocks - for(int j = 0; j < m_pBlocks.size() - uMaxNumberOfBlocksInMemory; j++) - { - typename std::map::iterator i; - typename std::map::iterator itUnloadBlock = m_pBlocks.begin(); - for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) - { - if(i->second.timestamp < itUnloadBlock->second.timestamp) - { - itUnloadBlock = i; - } - } - eraseBlock(itUnloadBlock); - } + flushAll(); } m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory; } @@ -376,60 +357,96 @@ } template - bool Volume::prefetchRegion(Region regPrefetch) + void Volume::prefetch(Region regPrefetch) { - Vector3DInt32 start; - for(int i = 0; i < 3; i++) start.setElement(i, regPrefetch.getLowerCorner().getElement(i) >> m_uBlockSideLengthPower); - Vector3DInt32 end; - for(int i = 0; i < 3; i++) end.setElement(i, regPrefetch.getUpperCorner().getElement(i) >> m_uBlockSideLengthPower); - Vector3DInt32 size = end-start + Vector3DInt32(1,1,1); - int32_t numblocks = size.getX() * size.getY() * size.getZ(); + Vector3DInt32 v3dStart; + for(int i = 0; i < 3; i++) + { + v3dStart.setElement(i, regPrefetch.getLowerCorner().getElement(i) >> m_uBlockSideLengthPower); + } + + Vector3DInt32 v3dEnd; + for(int i = 0; i < 3; i++) + { + v3dEnd.setElement(i, regPrefetch.getUpperCorner().getElement(i) >> m_uBlockSideLengthPower); + } + + Vector3DInt32 v3dSize = v3dEnd - v3dStart + Vector3DInt32(1,1,1); + int32_t numblocks = v3dSize.getX() * v3dSize.getY() * v3dSize.getZ(); if(numblocks > m_uMaxNumberOfBlocksInMemory) { - return false; + // cannot support the amount of blocks... so only load the maximum possible + numblocks = m_uMaxNumberOfBlocksInMemory; } - if(numblocks > (m_uMaxNumberOfBlocksInMemory - m_pBlocks.size())) { - // TODO: unload enough blocks to support the blocks that will be loaded. - } - for(int32_t x = start.getX(); x <= end.getX(); x++) { - for(int32_t y = start.getY(); y <= end.getY(); y++) { - for(int32_t z = start.getZ(); z <= end.getZ(); z++) { + for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++) + { + for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++) + { + for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) + { + Vector3DInt32 pos(x,y,z); + typename std::map::iterator itBlock = m_pBlocks.find(pos); + if(itBlock != m_pBlocks.end()) { + // already loaded, no need to load again + continue; + } + if(!numblocks) + { + // loading any more blocks would attempt to overflow the + // memory and therefore erase blocks we loaded in the beginning + return; + } + // load a block + numblocks--; Block* block = getUncompressedBlock(x,y,z); - } - } + } // for z + } // for y + } // for x + } + + template + void Volume::flushAll() + { + typename std::map::iterator i; + for(i = m_pBlocks.begin(); i != m_pBlocks.end(); eraseBlock(i++)) + { } - return true; } template - uint32_t Volume::flushRegion(Region regFlush) + void Volume::flush(Region regFlush) { - Vector3DInt32 start; - for(int i = 0; i < 3; i++) start.setElement(i, regFlush.getLowerCorner().getElement(i) >> m_uBlockSideLengthPower); - Vector3DInt32 end; - for(int i = 0; i < 3; i++) end.setElement(i, regFlush.getUpperCorner().getElement(i) >> m_uBlockSideLengthPower); - uint32_t count = 0; - for(int32_t x = start.getX(); x <= end.getX(); x++) { - for(int32_t y = start.getY(); y <= end.getY(); y++) { - for(int32_t z = start.getZ(); z <= end.getZ(); z++) { + Vector3DInt32 v3dStart; + for(int i = 0; i < 3; i++) + { + v3dStart.setElement(i, regFlush.getLowerCorner().getElement(i) >> m_uBlockSideLengthPower); + } + + Vector3DInt32 v3dEnd; + for(int i = 0; i < 3; i++) + { + v3dEnd.setElement(i, regFlush.getUpperCorner().getElement(i) >> m_uBlockSideLengthPower); + } + + for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++) + { + for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++) + { + for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) + { Vector3DInt32 pos(x,y,z); - if(m_v3dLastAccessedBlockPos == pos) { - m_pLastAccessedBlock = NULL; - } typename std::map::iterator itBlock = m_pBlocks.find(pos); if(itBlock == m_pBlocks.end()) { // not loaded, not unloading continue; } eraseBlock(itBlock); - count++; - } - } - } - if(count > ((std::numeric_limits::max)() >> (m_uBlockSideLengthPower*3))) { - // eh, this will overflow... I have no idea what to do here - return (std::numeric_limits::max)(); - } - return count << (m_uBlockSideLengthPower*3); + // eraseBlock might cause a call to getUncompressedBlock, which again sets m_pLastAccessedBlock + if(m_v3dLastAccessedBlockPos == pos) { + m_pLastAccessedBlock = NULL; + } + } // for z + } // for y + } // for x } template Index: library/PolyVoxCore/include/Volume.h =================================================================== --- library/PolyVoxCore/include/Volume.h (revision 1429) +++ library/PolyVoxCore/include/Volume.h (working copy) @@ -186,17 +186,18 @@ bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue); /// Sets the voxel at a 3D vector position bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue); - /// makes sure all the voxels in the given region are loaded + /// tries to load all voxels inside the given region /// if MaxNumberOfBlocksInMemory is not large enough to support the region - /// this function will return false and the volume is unchanged - /// if all the voxels in the given region are already loaded, this function will not do anything but still return true. + /// this function will only load part of the region. 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 blocks might be unloaded to make space for the new blocks - bool prefetchRegion(Region regPrefetch); + void prefetch(Region regPrefetch); /// attempts to unload all the voxels in the given region. /// there is no guarantee that any voxels are unloaded /// try unloading a region whose sidelengths are multiples of BlockSideLength - /// returns the number of voxels that were actually unloaded - uint32_t flushRegion(Region regFlush); + void flush(Region regFlush); + /// unloads all data + void flushAll(); void clearBlockCache(void); float calculateCompressionRatio(void); Index: examples/Paging/main.cpp =================================================================== --- examples/Paging/main.cpp (revision 1429) +++ examples/Paging/main.cpp (working copy) @@ -29,6 +29,7 @@ #include "SurfaceExtractor.h" #include "SurfaceMesh.h" #include "Volume.h" +#include "Filters.h" #include @@ -249,18 +250,17 @@ OpenGLWidget openGLWidget(0); openGLWidget.show(); - //Create an empty volume and then place a sphere in it + //If these lines don't compile, please try commenting them out and using the two lines after + //(you will need Boost for this). If you have to do this then please let us know in the forums as + //we rely on community feedback to keep the Boost version running. Volume volData(&load, &unload, 256); + //Volume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), + // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); volData.setMaxNumberOfUncompressedBlocks(64); - //If these two lines don't compile, please try commenting them out and using the two lines after - //(you will need Boost for this). If you have to do this then please let us know in the forums as - //we rely on community feedback to keep the Boost version running. //volData.dataRequiredHandler = &load; //volData.dataOverflowHandler = &unload; - //volData.dataRequiredHandler = polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2); - //volData.dataOverflowHandler = polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2); //volData.setMaxNumberOfUncompressedBlocks(4096); //createSphereInVolume(volData, 30); @@ -271,31 +271,39 @@ //volData.setBlockCacheSize(64); PolyVox::Region reg(Vector3DInt32(-255,0,0), Vector3DInt32(255,1024,255)); std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; - volData.prefetchRegion(reg); + volData.prefetch(reg); 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; PolyVox::Region reg2(Vector3DInt32(0,0,0), Vector3DInt32(500,500,500)); std::cout << "Flushing region: " << reg2.getLowerCorner() << " -> " << reg2.getUpperCorner() << std::endl; - uint32_t voxelsFlushed = volData.flushRegion(reg2); - Vector3DInt32 size = reg2.getUpperCorner() - reg2.getLowerCorner() + Vector3DInt32(1,1,1); - uint32_t voxelsFlushed2 = size.getX()*size.getY()*size.getZ(); - std::cout << voxelsFlushed << " Voxels were unloaded, while " << voxelsFlushed2 << " should have been unloaded" << std::endl; + volData.flush(reg2); 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; + std::cout << "Flushing entire volume" << std::endl; + volData.flushAll(); + 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; - /*srand(12345); - for(int ct = 0; ct < 1000; ct++) + srand(12345); + for(int ct = 0; ct < 100; ct++) { std::cout << ct << std::endl; - int x = rand() % volData.getWidth(); - int y = rand() % volData.getHeight(); - int z = rand() % volData.getDepth(); + int x = rand() % 256; + int y = rand() % 256; + int z = rand() % 256; int r = rand() % 20; createSphereInVolume(volData, Vector3DFloat(x,y,z), r); - }*/ + } + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(128,256,256))); + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(128,256,256))); + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(128,256,256))); + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(256,128,256))); + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(256,128,256))); + smoothRegion(volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(256,128,256))); + //Extract the surface SurfaceMesh mesh; //CubicSurfaceExtractorWithNormals surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);