601 lines
18 KiB
C++
601 lines
18 KiB
C++
/*******************************************************************************
|
|
Copyright (c) 2010 Matt 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.
|
|
*******************************************************************************/
|
|
|
|
#include "testvolume.h"
|
|
|
|
#include "PolyVox/FilePager.h"
|
|
#include "PolyVox/PagedVolume.h"
|
|
#include "PolyVox/RawVolume.h"
|
|
|
|
#include <QtGlobal>
|
|
#include <QtTest>
|
|
|
|
#include <random>
|
|
|
|
using namespace PolyVox;
|
|
|
|
// This is used to compute a value from a list of integers. We use it to
|
|
// make sure we get the expected result from a series of volume accesses.
|
|
inline int32_t cantorTupleFunction(int32_t previousResult, int32_t value)
|
|
{
|
|
return (( previousResult + value ) * ( previousResult + value + 1 ) + value ) / 2;
|
|
}
|
|
|
|
/*
|
|
* Funtions for testing iteration in a forwards direction
|
|
*/
|
|
|
|
// We allow user provided offset in this function so we can test the case when all samples are inside a volume and also the case when some samples are outside.
|
|
// This is important because samplers are often slower when outside the volume as they have to fall back on directly accessing the volume data.
|
|
template <typename VolumeType>
|
|
int32_t testDirectAccessWithWrappingForwards(const VolumeType* volume, Region region)
|
|
{
|
|
int32_t result = 0;
|
|
|
|
for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++)
|
|
{
|
|
for (int y = region.getLowerY(); y <= region.getUpperY(); y++)
|
|
{
|
|
for (int x = region.getLowerX(); x <= region.getUpperX(); x++)
|
|
{
|
|
//Three level loop now processes 27 voxel neighbourhood
|
|
for(int innerZ = -1; innerZ <=1; innerZ++)
|
|
{
|
|
for(int innerY = -1; innerY <=1; innerY++)
|
|
{
|
|
for(int innerX = -1; innerX <=1; innerX++)
|
|
{
|
|
result = cantorTupleFunction(result, volume->getVoxel(x + innerX, y + innerY, z + innerZ));
|
|
}
|
|
}
|
|
}
|
|
//End of inner loops
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename VolumeType>
|
|
int32_t testSamplersWithWrappingForwards(VolumeType* volume, Region region)
|
|
{
|
|
int32_t result = 0;
|
|
|
|
//Test the sampler move functions
|
|
typename VolumeType::Sampler sampler(volume);
|
|
|
|
for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++)
|
|
{
|
|
for (int y = region.getLowerY(); y <= region.getUpperY(); y++)
|
|
{
|
|
sampler.setPosition(region.getLowerX(), y, z);
|
|
for (int x = region.getLowerX(); x <= region.getUpperX(); x++)
|
|
{
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px0py1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px0py1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1py1nz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1py1nz());
|
|
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px0py0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px0py0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1py0pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1py0pz());
|
|
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px0py1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px0py1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel0px1py1pz());
|
|
result = cantorTupleFunction(result, sampler.peekVoxel1px1py1pz());
|
|
|
|
sampler.movePositiveX();
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Funtions for testing iteration in a backwards direction
|
|
*/
|
|
|
|
// We allow user provided offset in this function so we can test the case when all samples are inside a volume and also the case when some samples are outside.
|
|
// This is important because samplers are often slower when outside the volume as they have to fall back on directly accessing the volume data.
|
|
template <typename VolumeType>
|
|
int32_t testDirectAccessWithWrappingBackwards(const VolumeType* volume, Region region)
|
|
{
|
|
int32_t result = 0;
|
|
|
|
for (int z = region.getUpperZ(); z >= region.getLowerZ(); z--)
|
|
{
|
|
for (int y = region.getUpperY(); y >= region.getLowerY(); y--)
|
|
{
|
|
for (int x = region.getUpperX(); x >= region.getLowerX(); x--)
|
|
{
|
|
//Three level loop now processes 27 voxel neighbourhood
|
|
for(int innerZ = -1; innerZ <=1; innerZ++)
|
|
{
|
|
for(int innerY = -1; innerY <=1; innerY++)
|
|
{
|
|
for(int innerX = -1; innerX <=1; innerX++)
|
|
{
|
|
result = cantorTupleFunction(result, volume->getVoxel(x + innerX, y + innerY, z + innerZ));
|
|
}
|
|
}
|
|
}
|
|
//End of inner loops
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename VolumeType>
|
|
int32_t testSamplersWithWrappingBackwards(VolumeType* volume, Region region)
|
|
{
|
|
int32_t result = 0;
|
|
|
|
//Test the sampler move functions
|
|
typename VolumeType::Sampler xSampler(volume);
|
|
|
|
for (int z = region.getUpperZ(); z >= region.getLowerZ(); z--)
|
|
{
|
|
for (int y = region.getUpperY(); y >= region.getLowerY(); y--)
|
|
{
|
|
xSampler.setPosition(region.getUpperX(), y, z);
|
|
for (int x = region.getUpperX(); x >= region.getLowerX(); x--)
|
|
{
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1ny1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1ny1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1ny1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx0py1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px0py1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px0py1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1py1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1py1nz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1py1nz());
|
|
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1ny0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1ny0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1ny0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx0py0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px0py0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px0py0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1py0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1py0pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1py0pz());
|
|
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1ny1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1ny1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1ny1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx0py1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px0py1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px0py1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1nx1py1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel0px1py1pz());
|
|
result = cantorTupleFunction(result, xSampler.peekVoxel1px1py1pz());
|
|
|
|
xSampler.moveNegativeX();
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename VolumeType>
|
|
int32_t testDirectRandomAccess(const VolumeType* volume)
|
|
{
|
|
std::mt19937 rng;
|
|
int32_t result = 0;
|
|
|
|
for (uint32_t ct = 0; ct < 10000; ct++)
|
|
{
|
|
uint32_t rand = rng();
|
|
|
|
// Four random number between 0-255
|
|
uint32_t part0 = static_cast<int32_t>(rand & 0xFF);
|
|
int32_t part1 = static_cast<int32_t>((rand >> 8) & 0xFF);
|
|
int32_t part2 = static_cast<int32_t>((rand >> 16) & 0xFF);
|
|
int32_t part3 = static_cast<int32_t>((rand >> 24) & 0xFF);
|
|
|
|
result = cantorTupleFunction(result, volume->getVoxel(part0, part1, part2));
|
|
result = cantorTupleFunction(result, volume->getVoxel(part1, part2, part3));
|
|
result = cantorTupleFunction(result, volume->getVoxel(part2, part3, part0));
|
|
result = cantorTupleFunction(result, volume->getVoxel(part3, part0, part1));
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
TestVolume::TestVolume()
|
|
{
|
|
m_regVolume = Region(-57, -31, 12, 64, 96, 131); // Deliberatly awkward size
|
|
|
|
m_regInternal = m_regVolume;
|
|
m_regInternal.shiftLowerCorner(4, 2, 2);
|
|
m_regInternal.shiftUpperCorner(-3, -1, -2);
|
|
|
|
m_regExternal = m_regVolume;
|
|
m_regExternal.shiftLowerCorner(-1, -3, -2);
|
|
m_regExternal.shiftUpperCorner(2, 5, 4);
|
|
|
|
m_pFilePager = new FilePager<int32_t>(".");
|
|
|
|
//Create the volumes
|
|
m_pRawVolume = new RawVolume<int32_t>(m_regVolume);
|
|
m_pPagedVolume = new PagedVolume<int32_t>(m_pFilePager, 1 * 1024 * 1024, m_uChunkSideLength);
|
|
|
|
//Fill the volume with some data
|
|
for (int z = m_regVolume.getLowerZ(); z <= m_regVolume.getUpperZ(); z++)
|
|
{
|
|
for (int y = m_regVolume.getLowerY(); y <= m_regVolume.getUpperY(); y++)
|
|
{
|
|
for (int x = m_regVolume.getLowerX(); x <= m_regVolume.getUpperX(); x++)
|
|
{
|
|
int32_t value = x + y + z;
|
|
m_pRawVolume->setVoxel(x, y, z, value);
|
|
m_pPagedVolume->setVoxel(x, y, z, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note - We are reusing the FilePager for testing... watch out for conflicts with the main volume.
|
|
m_pPagedVolumeChunk = new PagedVolume<uint32_t>::Chunk(Vector3DInt32(10000, 10000, 10000), m_uChunkSideLength, nullptr);
|
|
std::mt19937 rng;
|
|
for (uint16_t z = 0; z < m_uChunkSideLength; z++)
|
|
{
|
|
for (uint16_t y = 0; y < m_uChunkSideLength; y++)
|
|
{
|
|
for (uint16_t x = 0; x < m_uChunkSideLength; x++)
|
|
{
|
|
m_pPagedVolumeChunk->setVoxel(x, y, z, static_cast<uint32_t>(rng()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TestVolume::~TestVolume()
|
|
{
|
|
delete m_pPagedVolumeChunk;
|
|
|
|
delete m_pRawVolume;
|
|
delete m_pPagedVolume;
|
|
|
|
delete m_pFilePager;
|
|
}
|
|
|
|
/*
|
|
* RawVolume Tests
|
|
*/
|
|
|
|
void TestVolume::testRawVolumeDirectAccessAllInternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingForwards(m_pRawVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(1004598054));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeSamplersAllInternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingForwards(m_pRawVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(1004598054));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeDirectAccessWithExternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingForwards(m_pRawVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(337227750));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeSamplersWithExternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingForwards(m_pRawVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(337227750));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeDirectAccessAllInternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingBackwards(m_pRawVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-269366578));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeSamplersAllInternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingBackwards(m_pRawVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-269366578));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeDirectAccessWithExternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingBackwards(m_pRawVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-993539594));
|
|
}
|
|
|
|
void TestVolume::testRawVolumeSamplersWithExternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingBackwards(m_pRawVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-993539594));
|
|
}
|
|
|
|
/*
|
|
* PagedVolume Tests
|
|
*/
|
|
|
|
void TestVolume::testPagedVolumeDirectAccessAllInternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingForwards(m_pPagedVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(1004598054));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeSamplersAllInternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingForwards(m_pPagedVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(1004598054));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeDirectAccessWithExternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingForwards(m_pPagedVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(337227750));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeSamplersWithExternalForwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingForwards(m_pPagedVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(337227750));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeDirectAccessAllInternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingBackwards(m_pPagedVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-269366578));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeSamplersAllInternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingBackwards(m_pPagedVolume, m_regInternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-269366578));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeDirectAccessWithExternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectAccessWithWrappingBackwards(m_pPagedVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-993539594));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeSamplersWithExternalBackwards()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testSamplersWithWrappingBackwards(m_pPagedVolume, m_regExternal);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-993539594));
|
|
}
|
|
|
|
/*
|
|
* Random access tests
|
|
*/
|
|
void TestVolume::testRawVolumeDirectRandomAccess()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectRandomAccess(m_pRawVolume);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(805464457));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeDirectRandomAccess()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testDirectRandomAccess(m_pPagedVolume);
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(805464457));
|
|
}
|
|
|
|
int32_t TestVolume::testPagedVolumeChunkAccess(uint16_t localityMask)
|
|
{
|
|
std::mt19937 rng;
|
|
int32_t sum = 0;
|
|
uint16_t x = 0;
|
|
uint16_t y = 0;
|
|
uint16_t z = 0;
|
|
|
|
// Used to constrain the range, as '&=m_uChunkSideLengthMask' should be faster than '%=m_uChunkSideLength'.
|
|
uint16_t m_uChunkSideLengthMask = m_uChunkSideLength - 1;
|
|
|
|
for (int32_t ct = 0; ct < 10000000; ct++)
|
|
{
|
|
// Random number generation is relatively slow compared to retireving a voxel, so if we are not
|
|
// careful the process of choosing which voxel to get can become slower than actually getting it.
|
|
// Therefore we use the same random number multiple times by getting different bits from it.
|
|
uint32_t rand = rng();
|
|
|
|
// We have 32 random bits and we make 27 (3*9) calls to getVoxel(). This means we
|
|
// stop using the lower bits before they all get set to zero from the right-shifting.
|
|
// An odd number means we have an imbalance between the number of times we go forward vs.
|
|
// backwards, so overall we will drift around the volume even if locality is constrained.
|
|
for (uint32_t i = 0; i < 3; i++)
|
|
{
|
|
x += rand & localityMask; // Move x forwardsby a small amount, limited by localityMask.
|
|
x &= m_uChunkSideLengthMask; // Ensure it is within the valid range.
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z); // Get the voxel value and use it.
|
|
rand >>= 1; // Shift the bits so we use different ones next time.
|
|
|
|
y -= rand & localityMask; // This one (and some others) are negative so sometimes we go backwards.
|
|
y &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
z += rand & localityMask;
|
|
z &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
x -= rand & localityMask;
|
|
x &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
y += rand & localityMask;
|
|
y &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
z -= rand & localityMask;
|
|
z &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
x += rand & localityMask;
|
|
x &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
y -= rand & localityMask;
|
|
y &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
|
|
z += rand & localityMask;
|
|
z &= m_uChunkSideLengthMask;
|
|
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
|
|
rand >>= 1;
|
|
}
|
|
}
|
|
|
|
// It's important to use the voxel values, otherwise
|
|
// the compiler optimizes out the calls to getVoxel().
|
|
return sum;
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeChunkLocalAccess()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testPagedVolumeChunkAccess(0x0003); // Small value for good locality
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(-158083685));
|
|
}
|
|
|
|
void TestVolume::testPagedVolumeChunkRandomAccess()
|
|
{
|
|
int32_t result = 0;
|
|
QBENCHMARK
|
|
{
|
|
result = testPagedVolumeChunkAccess(0xFFFF); // Large value for poor locality (random access)
|
|
}
|
|
QCOMPARE(result, static_cast<int32_t>(71649197));
|
|
}
|
|
|
|
QTEST_MAIN(TestVolume)
|