refactor: migrate voxel data storage to DataAllocator for CUDA

This commit is contained in:
AndreaRigoni
2026-02-28 10:05:39 +00:00
parent 07915295cb
commit 52580d8cde
14 changed files with 1484 additions and 1022 deletions

View File

@@ -22,3 +22,7 @@ set(LIBRARIES
)
uLib_add_tests(Math)
if(USE_CUDA)
set_source_files_properties(VoxImageFilterTest.cpp PROPERTIES LANGUAGE CUDA)
endif()

View File

@@ -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;
}