Skip to content

Commit b3aead3

Browse files
sifakismatthewdcong
authored andcommitted
Adding unittests for topological operations
* fixing discrepancies between OpenToNano/PointsToGrid constructions * dilate/inject/prune unittest * ws fix * adding MergeGrids unittest * key test --------- Co-authored-by: Efty Sifakis <esifakis@nvidia.com> Signed-off-by: Matthew Cong <mcong@nvidia.com>
1 parent 6f3f350 commit b3aead3

1 file changed

Lines changed: 113 additions & 1 deletion

File tree

nanovdb/nanovdb/unittest/TestNanoVDB.cu

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
#include <nanovdb/tools/cuda/GridChecksum.cuh>
1818
#include <nanovdb/tools/cuda/GridValidator.cuh>
1919
#include <nanovdb/tools/cuda/GridStats.cuh>
20-
//#include <nanovdb/tools/cuda/DilateVoxels.cuh>
20+
#include <nanovdb/tools/cuda/DilateGrid.cuh>
21+
#include <nanovdb/tools/cuda/MergeGrids.cuh>
22+
#include <nanovdb/tools/cuda/PruneGrid.cuh>
23+
#include <nanovdb/util/cuda/Injection.cuh>
2124
#include <nanovdb/util/cuda/Timer.h>
2225
#include <nanovdb/util/Timer.h>
2326
#include <nanovdb/io/IO.h>
@@ -3576,6 +3579,115 @@ TEST(TestNanoVDBCUDA, VoxelBlockManager_ValueOnIndex_UnifiedBuffer)
35763579
testVoxelBlockManager<nanovdb::ValueOnIndex,nanovdb::cuda::UnifiedBuffer>();
35773580
}// VoxelBlockManager_ValueOnIndex_UnifiedBuffer
35783581

3582+
TEST(TestNanoVDBCUDA, DilateInjectPrune_ValueOnIndex)
3583+
{
3584+
using BuildT = nanovdb::ValueOnIndex;
3585+
3586+
// Create an input (original) grid to use as input to dilation op
3587+
std::vector<nanovdb::Coord> inputPoints;
3588+
inputPoints.emplace_back(nanovdb::Coord{1,0,0}); // Added nodes after dilation: 3 root, 3 upper, 3 lower, 3 leaf
3589+
inputPoints.emplace_back(nanovdb::Coord{0,1,1}); // Added nodes after dilation: 1 root, 1 upper, 1 lower, 1 leaf
3590+
inputPoints.emplace_back(nanovdb::Coord{127,127,127}); // Added nodes after dilation: 7 lower, 7 leaf
3591+
auto inputBuffer = nanovdb::cuda::DeviceBuffer::create( inputPoints.size() * sizeof(nanovdb::Coord), nullptr, false);
3592+
EXPECT_FALSE(inputBuffer.data());
3593+
EXPECT_TRUE(inputBuffer.deviceData());
3594+
cudaCheck(cudaMemcpy(inputBuffer.deviceData(), inputPoints.data(), inputPoints.size() * sizeof(nanovdb::Coord), cudaMemcpyHostToDevice));
3595+
nanovdb::tools::cuda::PointsToGrid<BuildT> converter;
3596+
converter.setChecksum(nanovdb::CheckMode::Default);
3597+
auto inputHandle = converter.getHandle(static_cast<nanovdb::Coord*>(inputBuffer.deviceData()), inputPoints.size());
3598+
EXPECT_TRUE(inputHandle.deviceGrid<BuildT>());
3599+
auto inputGrid = inputHandle.deviceGrid<BuildT>();
3600+
EXPECT_FALSE(inputHandle.grid<BuildT>());
3601+
3602+
// Perform dilation
3603+
nanovdb::tools::cuda::DilateGrid<BuildT> dilator( inputGrid );
3604+
dilator.setOperation(nanovdb::tools::morphology::NN_FACE_EDGE_VERTEX);
3605+
dilator.setChecksum(nanovdb::CheckMode::Default);
3606+
dilator.setVerbose(0);
3607+
auto dilatedHandle = dilator.getHandle();
3608+
auto dilatedGrid = dilatedHandle.deviceGrid<BuildT>();
3609+
EXPECT_TRUE(dilatedGrid);
3610+
auto dilatedTreeData = nanovdb::util::cuda::DeviceGridTraits<BuildT>::getTreeData(dilatedGrid);
3611+
EXPECT_EQ(dilatedTreeData.mNodeCount[0], 13);
3612+
EXPECT_EQ(dilatedTreeData.mNodeCount[1], 12);
3613+
EXPECT_EQ(dilatedTreeData.mNodeCount[2], 5);
3614+
EXPECT_EQ(dilatedTreeData.mVoxelCount, 73);
3615+
3616+
// Create a prune mask (set bits correspond to retained voxels) from the occupancy of the original grid
3617+
auto maskBuffer = nanovdb::cuda::DeviceBuffer::create( dilatedTreeData.mNodeCount[0] * sizeof(nanovdb::Mask<3>), nullptr, false);
3618+
EXPECT_TRUE(maskBuffer.deviceData());
3619+
auto leafMasks = static_cast<nanovdb::Mask<3>*>(maskBuffer.deviceData());
3620+
constexpr unsigned int num_threads = 128;
3621+
unsigned int num_blocks = (static_cast<unsigned int>(dilatedTreeData.mNodeCount[0]) + num_threads - 1) / num_threads;
3622+
nanovdb::util::cuda::lambdaKernel<<<num_blocks, num_threads>>>(dilatedTreeData.mNodeCount[0],
3623+
nanovdb::util::cuda::InjectGridMaskFunctor<BuildT>(),
3624+
inputGrid, dilatedGrid, leafMasks);
3625+
3626+
// Prune with computed mask
3627+
nanovdb::tools::cuda::PruneGrid<BuildT> pruner( dilatedGrid, leafMasks );
3628+
pruner.setChecksum(nanovdb::CheckMode::Default);
3629+
pruner.setVerbose(0);
3630+
auto prunedHandle = pruner.getHandle();
3631+
auto prunedGrid = prunedHandle.deviceGrid<BuildT>();
3632+
EXPECT_TRUE(prunedGrid);
3633+
3634+
// The pruned grid should be identical to the original input
3635+
EXPECT_FALSE(prunedHandle.grid<BuildT>());
3636+
inputHandle.deviceDownload();
3637+
prunedHandle.deviceDownload();
3638+
EXPECT_TRUE(inputHandle.grid<BuildT>());
3639+
EXPECT_TRUE(prunedHandle.grid<BuildT>());
3640+
EXPECT_EQ(inputHandle.grid<BuildT>()->mChecksum.full(), prunedHandle.grid<BuildT>()->mChecksum.full());
3641+
}// DilateInjectPrune_ValueOnIndex
3642+
3643+
TEST(TestNanoVDBCUDA, MergeGrids_ValueOnIndex)
3644+
{
3645+
using BuildT = nanovdb::ValueOnIndex;
3646+
3647+
// Create the first input grid for the merge op
3648+
std::vector<nanovdb::Coord> inputPointsA;
3649+
for (int i = 0; i <= 2; i++)
3650+
for (int j = 0; j <= 2; j++)
3651+
for (int k = 0; k <= 2; k++)
3652+
inputPointsA.emplace_back(nanovdb::Coord{i-1, j*8-1, k*128}); // 4 upper, 12 lower, 18 leaf nodes
3653+
auto inputBufferA = nanovdb::cuda::DeviceBuffer::create( inputPointsA.size() * sizeof(nanovdb::Coord), nullptr, false);
3654+
EXPECT_FALSE(inputBufferA.data());
3655+
EXPECT_TRUE(inputBufferA.deviceData());
3656+
cudaCheck(cudaMemcpy(inputBufferA.deviceData(), inputPointsA.data(), inputPointsA.size() * sizeof(nanovdb::Coord), cudaMemcpyHostToDevice));
3657+
auto inputHandleA = nanovdb::tools::cuda::voxelsToGrid<BuildT>(static_cast<nanovdb::Coord*>(inputBufferA.deviceData()), inputPointsA.size());
3658+
EXPECT_TRUE(inputHandleA.deviceGrid<BuildT>());
3659+
auto inputGridA = inputHandleA.deviceGrid<BuildT>();
3660+
EXPECT_FALSE(inputHandleA.grid<BuildT>());
3661+
3662+
// Create the second input grid for the merge op
3663+
std::vector<nanovdb::Coord> inputPointsB;
3664+
for (int i = 0; i <= 2; i++)
3665+
for (int j = 0; j <= 2; j++)
3666+
for (int k = 0; k <= 2; k++)
3667+
inputPointsB.emplace_back(nanovdb::Coord{i, j*8-1, (k-1)*128}); // 4 upper, 6 lower, 9 leaf nodes
3668+
auto inputBufferB = nanovdb::cuda::DeviceBuffer::create( inputPointsB.size() * sizeof(nanovdb::Coord), nullptr, false);
3669+
EXPECT_FALSE(inputBufferB.data());
3670+
EXPECT_TRUE(inputBufferB.deviceData());
3671+
cudaCheck(cudaMemcpy(inputBufferB.deviceData(), inputPointsB.data(), inputPointsB.size() * sizeof(nanovdb::Coord), cudaMemcpyHostToDevice));
3672+
auto inputHandleB = nanovdb::tools::cuda::voxelsToGrid<BuildT>(static_cast<nanovdb::Coord*>(inputBufferB.deviceData()), inputPointsB.size());
3673+
EXPECT_TRUE(inputHandleB.deviceGrid<BuildT>());
3674+
auto inputGridB = inputHandleB.deviceGrid<BuildT>();
3675+
EXPECT_FALSE(inputHandleB.grid<BuildT>());
3676+
3677+
// Perform the merge operation
3678+
nanovdb::tools::cuda::MergeGrids<BuildT> merger( inputGridA, inputGridB );
3679+
merger.setChecksum(nanovdb::CheckMode::Disable);
3680+
merger.setVerbose(0);
3681+
auto mergedHandle = merger.getHandle();
3682+
auto mergedGrid = mergedHandle.deviceGrid<BuildT>();
3683+
EXPECT_TRUE(mergedGrid);
3684+
auto mergedTreeData = nanovdb::util::cuda::DeviceGridTraits<BuildT>::getTreeData(mergedGrid);
3685+
EXPECT_EQ(mergedTreeData.mNodeCount[0], 21);
3686+
EXPECT_EQ(mergedTreeData.mNodeCount[1], 14);
3687+
EXPECT_EQ(mergedTreeData.mNodeCount[2], 6);
3688+
EXPECT_EQ(mergedTreeData.mVoxelCount, 42); // Each input grid has 27 active voxels, 12 shared between the two
3689+
}// DilateInjectPrune_ValueOnIndex
3690+
35793691
TEST(TestNanoVDBCUDA, GridHandle_from_HostBuffer)
35803692
{
35813693
using namespace nanovdb;

0 commit comments

Comments
 (0)