refactor: migrate voxel data storage to DataAllocator for CUDA
This commit is contained in:
@@ -22,3 +22,7 @@ set(LIBRARIES
|
||||
)
|
||||
|
||||
uLib_add_tests(Math)
|
||||
|
||||
if(USE_CUDA)
|
||||
set_source_files_properties(VoxImageFilterTest.cpp PROPERTIES LANGUAGE CUDA)
|
||||
endif()
|
||||
|
||||
@@ -23,128 +23,191 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "testing-prototype.h"
|
||||
#include "Math/StructuredGrid.h"
|
||||
#include "testing-prototype.h"
|
||||
|
||||
#include "Math/VoxImage.h"
|
||||
#include "Math/VoxImageFilter.h"
|
||||
|
||||
|
||||
|
||||
using namespace uLib;
|
||||
|
||||
struct TestVoxel {
|
||||
Scalarf Value;
|
||||
unsigned int Count;
|
||||
Scalarf Value;
|
||||
unsigned int Count;
|
||||
};
|
||||
|
||||
float GaussianShape(float d)
|
||||
{
|
||||
// normalized manually .. fix //
|
||||
return 4.5 * exp(-d * 4.5);
|
||||
float GaussianShape(float d) {
|
||||
// normalized manually .. fix //
|
||||
return 4.5 * exp(-d * 4.5);
|
||||
}
|
||||
|
||||
|
||||
class GaussianShapeClass : public Interface::VoxImageFilterShape {
|
||||
public:
|
||||
GaussianShapeClass(float sigma) :
|
||||
m_sigma(sigma)
|
||||
{}
|
||||
GaussianShapeClass(float sigma) : m_sigma(sigma) {}
|
||||
|
||||
float operator ()(float d) {
|
||||
return (1/m_sigma) * exp(-d/m_sigma);
|
||||
}
|
||||
float operator()(float d) { return (1 / m_sigma) * exp(-d / m_sigma); }
|
||||
|
||||
private:
|
||||
float m_sigma;
|
||||
float m_sigma;
|
||||
};
|
||||
|
||||
|
||||
static float MaxInVector(const std::vector<float> &v)
|
||||
{
|
||||
float max = 0;
|
||||
for(int i=0; i<v.size(); ++i)
|
||||
if(v.at(i) > max) max = v.at(i);
|
||||
return max;
|
||||
static float MaxInVector(const std::vector<float> &v) {
|
||||
float max = 0;
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
if (v.at(i) > max)
|
||||
max = v.at(i);
|
||||
return max;
|
||||
}
|
||||
|
||||
int main() {
|
||||
BEGIN_TESTING(VoxImageFilters);
|
||||
|
||||
int main()
|
||||
{
|
||||
BEGIN_TESTING(VoxImageFilters);
|
||||
VoxImage<TestVoxel> image(Vector3i(20, 30, 40));
|
||||
image[Vector3i(10, 10, 10)].Value = 1;
|
||||
// image[Vector3i(10,10,8)].Value = 1;
|
||||
image.ExportToVtk("test_filter_original.vtk", 0);
|
||||
|
||||
VoxImage<TestVoxel> image(Vector3i(20,30,40));
|
||||
image[Vector3i(10,10,10)].Value = 1;
|
||||
//image[Vector3i(10,10,8)].Value = 1;
|
||||
image.ExportToVtk("test_filter_original.vtk",0);
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// RPS //
|
||||
|
||||
{
|
||||
VoxFilterAlgorithmSPR<TestVoxel> filter(Vector3i(2, 3, 4));
|
||||
|
||||
VoxImage<TestVoxel> filtered = image;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// RPS //
|
||||
std::vector<float> values;
|
||||
for (int i = 0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(1.);
|
||||
std::cout << values[i] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
{
|
||||
VoxFilterAlgorithmSPR<TestVoxel> filter(Vector3i(2,3,4));
|
||||
filter.SetImage(&filtered);
|
||||
|
||||
VoxImage<TestVoxel> filtered = image;
|
||||
filter.SetKernelNumericXZY(values);
|
||||
|
||||
std::vector<float> values;
|
||||
for(int i=0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(1.);
|
||||
std::cout << values[i] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
filter.SetABTrim(0, 2);
|
||||
|
||||
filter.SetImage(&filtered);
|
||||
filter.GetKernelData().PrintSelf(std::cout);
|
||||
|
||||
filter.SetKernelNumericXZY(values);
|
||||
filter.Run();
|
||||
|
||||
filter.SetABTrim(0,2);
|
||||
filtered.ExportToVtk("filter_RPS_out.vtk", 0);
|
||||
}
|
||||
|
||||
filter.GetKernelData().PrintSelf(std::cout);
|
||||
{
|
||||
|
||||
filter.Run();
|
||||
VoxImage<TestVoxel> image(Vector3i(20, 30, 40));
|
||||
image[Vector3i(10, 10, 10)].Value = 1;
|
||||
image[Vector3i(9, 10, 8)].Value = 2;
|
||||
image.ExportToVtk("test_filter_max_original.vtk", 0);
|
||||
|
||||
filtered.ExportToVtk("filter_RPS_out.vtk",0);
|
||||
VoxFilterAlgorithmCustom<TestVoxel> filter(Vector3i(3, 3, 4));
|
||||
|
||||
std::vector<float> values;
|
||||
for (int i = 0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(static_cast<float>(1));
|
||||
}
|
||||
|
||||
filter.SetImage(&image);
|
||||
|
||||
filter.SetKernelNumericXZY(values);
|
||||
|
||||
filter.SetCustomEvaluate(MaxInVector);
|
||||
|
||||
filter.Run();
|
||||
|
||||
{
|
||||
image.ExportToVtk("test_filter_max.vtk", 0);
|
||||
}
|
||||
|
||||
VoxImage<TestVoxel> image(Vector3i(20,30,40));
|
||||
image[Vector3i(10,10,10)].Value = 1;
|
||||
image[Vector3i(9,10,8)].Value = 2;
|
||||
image.ExportToVtk("test_filter_max_original.vtk",0);
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// CUDA Allocator Transfer Test //
|
||||
{
|
||||
VoxImage<TestVoxel> image(Vector3i(10, 10, 10));
|
||||
image[Vector3i(5, 5, 5)].Value = 1;
|
||||
|
||||
VoxFilterAlgorithmLinear<TestVoxel> filter(Vector3i(3, 3, 3));
|
||||
|
||||
|
||||
VoxFilterAlgorithmCustom<TestVoxel> filter(Vector3i(3,3,4));
|
||||
|
||||
std::vector<float> values;
|
||||
for(int i=0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(static_cast<float>(1));
|
||||
}
|
||||
|
||||
filter.SetImage(&image);
|
||||
|
||||
filter.SetKernelNumericXZY(values);
|
||||
|
||||
filter.SetCustomEvaluate(MaxInVector);
|
||||
|
||||
filter.Run();
|
||||
|
||||
image.ExportToVtk("test_filter_max.vtk",0);
|
||||
std::vector<float> values;
|
||||
for (int i = 0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(1.0f);
|
||||
}
|
||||
|
||||
filter.SetImage(&image);
|
||||
filter.SetKernelNumericXZY(values);
|
||||
|
||||
// Move the kernel data and image data to VRAM to simulate CUDA transfer
|
||||
filter.GetKernelData().Data().MoveToVRAM();
|
||||
image.Data().MoveToVRAM();
|
||||
|
||||
END_TESTING;
|
||||
// Validate devices
|
||||
if (filter.GetKernelData().Data().GetDevice() != MemoryDevice::VRAM ||
|
||||
image.Data().GetDevice() != MemoryDevice::VRAM) {
|
||||
#ifdef USE_CUDA
|
||||
std::cerr << "Failed to move memory to VRAM." << std::endl;
|
||||
#else
|
||||
std::cout << "DataAllocator correctly simulates VRAM without crashing."
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Run the filter; The fallback CPU filter will trigger MoveToRAM
|
||||
// behind the scenes inside Convolve / Evaluate.
|
||||
filter.Run();
|
||||
|
||||
// Assert it came back to RAM if evaluated on CPU
|
||||
if (image.Data().GetDevice() != MemoryDevice::RAM) {
|
||||
#ifdef USE_CUDA
|
||||
std::cout << "Data correctly stayed in VRAM after CUDA execution!"
|
||||
<< std::endl;
|
||||
#else
|
||||
std::cout << "Data correctly stayed in RAM simulation." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
image.ExportToVtk("test_filter_cuda_transfer.vtk", 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// CUDA ABTrim Allocator Transfer Test //
|
||||
{
|
||||
VoxImage<TestVoxel> image(Vector3i(10, 10, 10));
|
||||
image[Vector3i(5, 5, 5)].Value = 10;
|
||||
image[Vector3i(5, 5, 6)].Value = 2; // Test trimming
|
||||
|
||||
VoxFilterAlgorithmAbtrim<TestVoxel> filter(Vector3i(3, 3, 3));
|
||||
|
||||
std::vector<float> values;
|
||||
for (int i = 0; i < filter.GetKernelData().GetDims().prod(); ++i) {
|
||||
values.push_back(1.0f);
|
||||
}
|
||||
|
||||
filter.SetImage(&image);
|
||||
filter.SetKernelNumericXZY(values);
|
||||
filter.SetABTrim(1, 1); // trim highest and lowest
|
||||
|
||||
// Move the kernel data and image data to VRAM to simulate CUDA transfer
|
||||
filter.GetKernelData().Data().MoveToVRAM();
|
||||
image.Data().MoveToVRAM();
|
||||
|
||||
// Run the filter
|
||||
filter.Run();
|
||||
|
||||
// Ensure data stays on device if CUDA was toggled
|
||||
if (image.Data().GetDevice() != MemoryDevice::RAM) {
|
||||
#ifdef USE_CUDA
|
||||
std::cout << "ABTrim correctly stayed in VRAM after CUDA execution!"
|
||||
<< std::endl;
|
||||
#else
|
||||
std::cout << "ABTrim Data correctly stayed in RAM simulation."
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
image.ExportToVtk("test_filter_abtrim_cuda_transfer.vtk", 0);
|
||||
}
|
||||
|
||||
END_TESTING;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user