|
17 | 17 | #include <nanovdb/tools/cuda/GridChecksum.cuh> |
18 | 18 | #include <nanovdb/tools/cuda/GridValidator.cuh> |
19 | 19 | #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> |
21 | 24 | #include <nanovdb/util/cuda/Timer.h> |
22 | 25 | #include <nanovdb/util/Timer.h> |
23 | 26 | #include <nanovdb/io/IO.h> |
@@ -3576,6 +3579,115 @@ TEST(TestNanoVDBCUDA, VoxelBlockManager_ValueOnIndex_UnifiedBuffer) |
3576 | 3579 | testVoxelBlockManager<nanovdb::ValueOnIndex,nanovdb::cuda::UnifiedBuffer>(); |
3577 | 3580 | }// VoxelBlockManager_ValueOnIndex_UnifiedBuffer |
3578 | 3581 |
|
| 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 | + |
3579 | 3691 | TEST(TestNanoVDBCUDA, GridHandle_from_HostBuffer) |
3580 | 3692 | { |
3581 | 3693 | using namespace nanovdb; |
|
0 commit comments