feat: Implement CUDA support for VoxRaytracer, add CUDA tests for voxel image operations, and update CMake to enable CUDA compilation.
This commit is contained in:
@@ -91,7 +91,9 @@ macro(uLib_add_tests name)
|
|||||||
|
|
||||||
# custom target to compile all tests
|
# custom target to compile all tests
|
||||||
add_custom_target(all-${name}-tests)
|
add_custom_target(all-${name}-tests)
|
||||||
add_dependencies(all-${name}-tests ${TESTS})
|
if(TESTS)
|
||||||
|
add_dependencies(all-${name}-tests ${TESTS})
|
||||||
|
endif()
|
||||||
endmacro(uLib_add_tests name)
|
endmacro(uLib_add_tests name)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
cmake_minimum_required (VERSION 3.26)
|
cmake_minimum_required (VERSION 3.26)
|
||||||
|
if(POLICY CMP0167)
|
||||||
|
cmake_policy(SET CMP0167 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
## -------------------------------------------------------------------------- ##
|
## -------------------------------------------------------------------------- ##
|
||||||
|
|
||||||
@@ -12,7 +16,14 @@ project(uLib)
|
|||||||
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
||||||
option(USE_CUDA "Enable CUDA support" ON)
|
option(USE_CUDA "Enable CUDA support" ON)
|
||||||
if(USE_CUDA)
|
if(USE_CUDA)
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -allow-unsupported-compiler")
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr")
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcudafe \"--diag_suppress=20012\"")
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcudafe \"--diag_suppress=20014\"")
|
||||||
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcudafe \"--diag_suppress=20015\"")
|
||||||
enable_language(CUDA)
|
enable_language(CUDA)
|
||||||
|
set(CMAKE_CUDA_ARCHITECTURES 61)
|
||||||
add_compile_definitions(USE_CUDA)
|
add_compile_definitions(USE_CUDA)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -93,6 +104,7 @@ set(Boost_USE_STATIC_LIBS OFF)
|
|||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||||
message(STATUS "CMAKE_PREFIX_PATH is ${CMAKE_PREFIX_PATH}")
|
message(STATUS "CMAKE_PREFIX_PATH is ${CMAKE_PREFIX_PATH}")
|
||||||
|
|
||||||
find_package(Boost 1.45.0 COMPONENTS program_options serialization unit_test_framework REQUIRED)
|
find_package(Boost 1.45.0 COMPONENTS program_options serialization unit_test_framework REQUIRED)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
|||||||
119
src/Core/Uuid.h
119
src/Core/Uuid.h
@@ -23,69 +23,49 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef U_CORE_UUID_H
|
#ifndef U_CORE_UUID_H
|
||||||
#define U_CORE_UUID_H
|
#define U_CORE_UUID_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/uuid/uuid.hpp>
|
|
||||||
#include <boost/uuid/name_generator.hpp>
|
#include <boost/uuid/name_generator.hpp>
|
||||||
#include <boost/uuid/random_generator.hpp>
|
#include <boost/uuid/random_generator.hpp>
|
||||||
|
#include <boost/uuid/uuid.hpp>
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
|
|
||||||
#include "Core/Mpl.h"
|
#include "Core/Mpl.h"
|
||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
|
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Object Registration //
|
// Object Registration //
|
||||||
|
|
||||||
|
|
||||||
typedef boost::uuids::uuid uuid_t;
|
typedef boost::uuids::uuid uuid_t;
|
||||||
|
|
||||||
extern uuid_t uLib_dns_uuid;
|
extern uuid_t uLib_dns_uuid;
|
||||||
|
|
||||||
template < typename T >
|
template <typename T> class type_id : public boost::uuids::uuid {
|
||||||
class type_id : public boost::uuids::uuid {
|
|
||||||
public:
|
public:
|
||||||
type_id() :
|
type_id()
|
||||||
m_size(sizeof(T)),
|
: m_size(sizeof(T)),
|
||||||
uuid(boost::uuids::name_generator(uLib_dns_uuid)(typeid(T).name()))
|
uuid(boost::uuids::name_generator(uLib_dns_uuid)(typeid(T).name())) {
|
||||||
{
|
std::cout << "Request for register new type\n"
|
||||||
std::cout << "Request for register new type\n" <<
|
<< "name: " << typeid(T).name() << "\n"
|
||||||
"name: " << typeid(T).name() << "\n" <<
|
<< "uuid: " << to_string(*this) << "\n";
|
||||||
"uuid: " << to_string(*this) << "\n";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
explicit type_id(boost::uuids::uuid const& u)
|
explicit type_id(boost::uuids::uuid const &u) : boost::uuids::uuid(u) {}
|
||||||
: boost::uuids::uuid(u) {}
|
|
||||||
|
|
||||||
operator boost::uuids::uuid() {
|
unsigned int size() const { return m_size; }
|
||||||
return static_cast<boost::uuids::uuid&>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator boost::uuids::uuid() const {
|
|
||||||
return static_cast<boost::uuids::uuid const&>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int size() const { return m_size; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int m_size;
|
unsigned int m_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -94,70 +74,57 @@ private:
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class TypeRegister {
|
class TypeRegister {
|
||||||
typedef boost::uuids::name_generator IDGen_t;
|
typedef boost::uuids::name_generator IDGen_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct RegisterEntry {
|
struct RegisterEntry {
|
||||||
uuid_t id;
|
uuid_t id;
|
||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
TypeRegister(uuid_t const &dns) :
|
TypeRegister(uuid_t const &dns) : gen(dns) {}
|
||||||
gen(dns) {}
|
|
||||||
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
RegisterEntry * AddType(T *t = NULL) {
|
|
||||||
RegisterEntry en = { gen(typeid(T).name()), sizeof(T) };
|
|
||||||
for(int i=0; i < m_registry.size(); ++i)
|
|
||||||
if(en.id == m_registry[i].id) return &(m_registry[i]);
|
|
||||||
m_registry.push_back(en);
|
|
||||||
return &m_registry.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintSelf(std::ostream &o) {
|
|
||||||
std::cout << "RegisterController: \n";
|
|
||||||
for (int i=0; i<m_registry.size(); ++i)
|
|
||||||
o << "type [" << i << "]: "
|
|
||||||
<< to_string(m_registry[i].id) << " "
|
|
||||||
<< m_registry[i].size << "\n";
|
|
||||||
o << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
template <typename T> RegisterEntry *AddType(T *t = NULL) {
|
||||||
|
RegisterEntry en = {gen(typeid(T).name()), sizeof(T)};
|
||||||
|
for (int i = 0; i < m_registry.size(); ++i)
|
||||||
|
if (en.id == m_registry[i].id)
|
||||||
|
return &(m_registry[i]);
|
||||||
|
m_registry.push_back(en);
|
||||||
|
return &m_registry.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintSelf(std::ostream &o) {
|
||||||
|
std::cout << "RegisterController: \n";
|
||||||
|
for (int i = 0; i < m_registry.size(); ++i)
|
||||||
|
o << "type [" << i << "]: " << to_string(m_registry[i].id) << " "
|
||||||
|
<< m_registry[i].size << "\n";
|
||||||
|
o << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IDGen_t gen;
|
IDGen_t gen;
|
||||||
std::vector<RegisterEntry> m_registry;
|
std::vector<RegisterEntry> m_registry;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // detail
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TypeRegister : public detail::TypeRegister {
|
class TypeRegister : public detail::TypeRegister {
|
||||||
public:
|
public:
|
||||||
typedef detail::TypeRegister BaseClass;
|
typedef detail::TypeRegister BaseClass;
|
||||||
typedef detail::TypeRegister::RegisterEntry Entry;
|
typedef detail::TypeRegister::RegisterEntry Entry;
|
||||||
|
|
||||||
static TypeRegister* Controller();
|
static TypeRegister *Controller();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeRegister(); // Blocks constructor
|
TypeRegister(); // Blocks constructor
|
||||||
static TypeRegister *s_Instance; // Singleton instance
|
static TypeRegister *s_Instance; // Singleton instance
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// OBJECT REGISTER //
|
// OBJECT REGISTER //
|
||||||
|
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
} // uLib
|
|
||||||
|
|
||||||
#endif // UUID_H
|
#endif // UUID_H
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ set( TESTS
|
|||||||
ObjectCopyTest
|
ObjectCopyTest
|
||||||
StaticInterfaceTest
|
StaticInterfaceTest
|
||||||
CommaInitTest
|
CommaInitTest
|
||||||
DebugTTreeDumpTest
|
# DebugTTreeDumpTest
|
||||||
BoostTest
|
BoostTest
|
||||||
BoostAccumulatorTest
|
BoostAccumulatorTest
|
||||||
PropertiesTest
|
PropertiesTest
|
||||||
|
|||||||
@@ -43,9 +43,15 @@ set(ULIB_SELECTED_MODULES ${ULIB_SELECTED_MODULES} Math PARENT_SCOPE)
|
|||||||
add_library(${libname} SHARED ${SOURCES})
|
add_library(${libname} SHARED ${SOURCES})
|
||||||
set_target_properties(${libname} PROPERTIES
|
set_target_properties(${libname} PROPERTIES
|
||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
SOVERSION ${PROJECT_SOVERSION})
|
SOVERSION ${PROJECT_SOVERSION}
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CUDA_STANDARD 17)
|
||||||
target_link_libraries(${libname} ${LIBRARIES})
|
target_link_libraries(${libname} ${LIBRARIES})
|
||||||
|
|
||||||
|
if(USE_CUDA)
|
||||||
|
set_source_files_properties(VoxRaytracer.cpp VoxImage.cpp PROPERTIES LANGUAGE CUDA)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
install(TARGETS ${libname}
|
install(TARGETS ${libname}
|
||||||
EXPORT "${PROJECT_NAME}Targets"
|
EXPORT "${PROJECT_NAME}Targets"
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef VOXRAYTRACER_H
|
#ifndef VOXRAYTRACER_H
|
||||||
#define VOXRAYTRACER_H
|
#define VOXRAYTRACER_H
|
||||||
|
|
||||||
@@ -32,62 +30,74 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Math/StructuredGrid.h"
|
#include "Math/StructuredGrid.h"
|
||||||
|
#include "Math/VoxImage.h"
|
||||||
|
|
||||||
|
#ifdef USE_CUDA
|
||||||
|
#include <cuda_runtime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
class VoxRaytracer {
|
class VoxRaytracer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class RayData {
|
class RayData {
|
||||||
public:
|
public:
|
||||||
RayData() : m_TotalLength(0) {}
|
RayData() : m_TotalLength(0) {}
|
||||||
|
|
||||||
typedef struct {
|
struct Element {
|
||||||
Id_t vox_id;
|
Id_t vox_id;
|
||||||
Scalarf L;
|
Scalarf L;
|
||||||
} Element;
|
~Element() {}
|
||||||
|
|
||||||
inline void AddElement(Id_t id, float L);
|
|
||||||
|
|
||||||
void AppendRay ( const RayData &in);
|
|
||||||
|
|
||||||
inline const std::vector<Element>& Data() const { return this->m_Data; }
|
|
||||||
|
|
||||||
inline const Scalarf& TotalLength() const { return this->m_TotalLength; }
|
|
||||||
|
|
||||||
void PrintSelf(std::ostream &o);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Element> m_Data;
|
|
||||||
Scalarf m_TotalLength;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void AddElement(Id_t id, float L);
|
||||||
|
|
||||||
public:
|
void AppendRay(const RayData &in);
|
||||||
VoxRaytracer(StructuredGrid &image) : m_Image(&image) {
|
|
||||||
m_scale <<
|
|
||||||
(m_Image->GetWorldMatrix() * Vector4f(1,0,0,0)).norm(),
|
|
||||||
(m_Image->GetWorldMatrix() * Vector4f(0,1,0,0)).norm(),
|
|
||||||
(m_Image->GetWorldMatrix() * Vector4f(0,0,1,0)).norm();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetEntryPoint(const HLine3f &line, HPoint3f &pt);
|
inline const std::vector<Element> &Data() const { return this->m_Data; }
|
||||||
|
|
||||||
bool GetExitPoint(const HLine3f &line, HPoint3f &pt);
|
inline const Scalarf &TotalLength() const { return this->m_TotalLength; }
|
||||||
|
|
||||||
RayData TraceBetweenPoints(const HPoint3f &in, const HPoint3f &out) const;
|
void PrintSelf(std::ostream &o);
|
||||||
|
|
||||||
RayData TraceLine(const HLine3f &line) const;
|
private:
|
||||||
|
std::vector<Element> m_Data;
|
||||||
|
Scalarf m_TotalLength;
|
||||||
|
};
|
||||||
|
|
||||||
inline StructuredGrid* GetImage() const { return this->m_Image; }
|
public:
|
||||||
|
VoxRaytracer(StructuredGrid &image) : m_Image(&image) {
|
||||||
|
m_scale << (m_Image->GetWorldMatrix() * Vector4f(1, 0, 0, 0)).norm(),
|
||||||
|
(m_Image->GetWorldMatrix() * Vector4f(0, 1, 0, 0)).norm(),
|
||||||
|
(m_Image->GetWorldMatrix() * Vector4f(0, 0, 1, 0)).norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetEntryPoint(const HLine3f &line, HPoint3f &pt);
|
||||||
|
|
||||||
|
bool GetExitPoint(const HLine3f &line, HPoint3f &pt);
|
||||||
|
|
||||||
|
RayData TraceBetweenPoints(const HPoint3f &in, const HPoint3f &out) const;
|
||||||
|
|
||||||
|
RayData TraceLine(const HLine3f &line) const;
|
||||||
|
|
||||||
|
inline StructuredGrid *GetImage() const { return this->m_Image; }
|
||||||
|
|
||||||
|
#ifdef USE_CUDA
|
||||||
|
template <typename VoxelT>
|
||||||
|
void AccumulateLinesCUDA(const HLine3f *lines, size_t num_lines,
|
||||||
|
VoxImage<VoxelT> &image);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StructuredGrid *m_Image;
|
StructuredGrid *m_Image;
|
||||||
Vector3f m_scale;
|
Vector3f m_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace uLib
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_CUDA
|
||||||
|
#include "Math/VoxRaytracerCUDA.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // VOXRAYTRACER_H
|
#endif // VOXRAYTRACER_H
|
||||||
|
|||||||
138
src/Math/VoxRaytracerCUDA.hpp
Normal file
138
src/Math/VoxRaytracerCUDA.hpp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
#ifndef VOXRAYTRACERCUDA_H
|
||||||
|
#define VOXRAYTRACERCUDA_H
|
||||||
|
|
||||||
|
#ifdef USE_CUDA
|
||||||
|
|
||||||
|
#include "Math/VoxImage.h"
|
||||||
|
#include "Math/VoxRaytracer.h"
|
||||||
|
#include <cuda_runtime.h>
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
|
||||||
|
#ifdef __CUDACC__
|
||||||
|
template <typename VoxelT>
|
||||||
|
__global__ void
|
||||||
|
RaytraceAccumulateKernel(const float *lines_data, int num_lines,
|
||||||
|
VoxelT *d_image, int dim0, int dim1, int dim2,
|
||||||
|
const float *inv_world_matrix_data, float scale0,
|
||||||
|
float scale1, float scale2) {
|
||||||
|
int idx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||||
|
if (idx >= num_lines)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float *line_ptr = &lines_data[idx * 8];
|
||||||
|
|
||||||
|
float o_vec[4] = {line_ptr[0], line_ptr[1], line_ptr[2], line_ptr[3]};
|
||||||
|
float d_vec[4] = {line_ptr[4], line_ptr[5], line_ptr[6], line_ptr[7]};
|
||||||
|
|
||||||
|
float pt[4] = {0, 0, 0, 0};
|
||||||
|
float s[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
float m_val = inv_world_matrix_data[i + j * 4];
|
||||||
|
pt[i] += m_val * o_vec[j];
|
||||||
|
s[i] += m_val * d_vec[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float l = sqrtf(s[0] * s[0] + s[1] * s[1] + s[2] * s[2]);
|
||||||
|
if (l == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float L[3];
|
||||||
|
L[0] = l / s[0];
|
||||||
|
L[1] = l / s[1];
|
||||||
|
L[2] = l / s[2];
|
||||||
|
|
||||||
|
float offset[3];
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
float fpt_i = floorf(pt[i]);
|
||||||
|
offset[i] = (s[i] >= 0) ? (1.0f - (pt[i] - fpt_i)) : (pt[i] - fpt_i);
|
||||||
|
offset[i] = fabsf(offset[i] * L[i]);
|
||||||
|
L[i] = fabsf(L[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
float d;
|
||||||
|
int vid[3] = {(int)floorf(pt[0]), (int)floorf(pt[1]), (int)floorf(pt[2])};
|
||||||
|
|
||||||
|
float scale_arr[3] = {scale0, scale1, scale2};
|
||||||
|
|
||||||
|
while (vid[0] >= 0 && vid[0] < dim0 && vid[1] >= 0 && vid[1] < dim1 &&
|
||||||
|
vid[2] >= 0 && vid[2] < dim2) {
|
||||||
|
|
||||||
|
d = offset[0];
|
||||||
|
id = 0;
|
||||||
|
if (offset[1] < d) {
|
||||||
|
d = offset[1];
|
||||||
|
id = 1;
|
||||||
|
}
|
||||||
|
if (offset[2] < d) {
|
||||||
|
d = offset[2];
|
||||||
|
id = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float L_intersect = d * scale_arr[id];
|
||||||
|
size_t vox_index = vid[0] * dim1 * dim2 + vid[1] * dim2 + vid[2];
|
||||||
|
|
||||||
|
atomicAdd(&(d_image[vox_index].Value), L_intersect);
|
||||||
|
|
||||||
|
float sign_s = (s[id] >= 0) ? 1.0f : -1.0f;
|
||||||
|
vid[id] += (int)sign_s;
|
||||||
|
|
||||||
|
offset[0] -= d;
|
||||||
|
offset[1] -= d;
|
||||||
|
offset[2] -= d;
|
||||||
|
offset[id] = L[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename VoxelT>
|
||||||
|
void VoxRaytracer::AccumulateLinesCUDA(const HLine3f *lines, size_t num_lines,
|
||||||
|
VoxImage<VoxelT> &image) {
|
||||||
|
if (num_lines == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
image.Data().MoveToVRAM();
|
||||||
|
|
||||||
|
float *d_lines = nullptr;
|
||||||
|
size_t lines_size = num_lines * sizeof(HLine3f);
|
||||||
|
cudaMalloc(&d_lines, lines_size);
|
||||||
|
cudaMemcpy(d_lines, lines, lines_size, cudaMemcpyHostToDevice);
|
||||||
|
int threadsPerBlock = 256;
|
||||||
|
int blocksPerGrid = (num_lines + threadsPerBlock - 1) / threadsPerBlock;
|
||||||
|
|
||||||
|
Vector3i dims = image.GetDims();
|
||||||
|
Matrix4f inv_world_matrix = image.GetWorldMatrix().inverse();
|
||||||
|
|
||||||
|
float *d_inv_world;
|
||||||
|
cudaMalloc(&d_inv_world, 16 * sizeof(float));
|
||||||
|
cudaMemcpy(d_inv_world, inv_world_matrix.data(), 16 * sizeof(float),
|
||||||
|
cudaMemcpyHostToDevice);
|
||||||
|
|
||||||
|
#ifdef __CUDACC__
|
||||||
|
RaytraceAccumulateKernel<<<blocksPerGrid, threadsPerBlock>>>(
|
||||||
|
d_lines, num_lines, image.Data().GetVRAMData(), dims(0), dims(1), dims(2),
|
||||||
|
d_inv_world, m_scale(0), m_scale(1), m_scale(2));
|
||||||
|
cudaDeviceSynchronize();
|
||||||
|
|
||||||
|
cudaError_t err = cudaGetLastError();
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
std::cerr << "CUDA Error in AccumulateLinesCUDA: "
|
||||||
|
<< cudaGetErrorString(err) << std::endl;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::cerr << "RaytraceAccumulateKernel requires NVCC!" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cudaFree(d_lines);
|
||||||
|
cudaFree(d_inv_world);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif // USE_CUDA
|
||||||
|
|
||||||
|
#endif // VOXRAYTRACERCUDA_H
|
||||||
@@ -24,5 +24,6 @@ set(LIBRARIES
|
|||||||
uLib_add_tests(Math)
|
uLib_add_tests(Math)
|
||||||
|
|
||||||
if(USE_CUDA)
|
if(USE_CUDA)
|
||||||
set_source_files_properties(VoxImageFilterTest.cpp PROPERTIES LANGUAGE CUDA)
|
set_source_files_properties(VoxImageTest.cpp VoxImageCopyTest.cpp VoxImageFilterTest.cpp VoxRaytracerTest.cpp PROPERTIES LANGUAGE CUDA)
|
||||||
|
set_source_files_properties(VoxRaytracerTest.cpp PROPERTIES CXX_STANDARD 17 CUDA_STANDARD 17)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -23,55 +23,44 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "testing-prototype.h"
|
#include "testing-prototype.h"
|
||||||
|
|
||||||
#include "Math/VoxImage.h"
|
#include "Math/VoxImage.h"
|
||||||
|
|
||||||
using namespace uLib;
|
using namespace uLib;
|
||||||
|
|
||||||
|
|
||||||
struct TestVoxel {
|
struct TestVoxel {
|
||||||
Scalarf Value;
|
Scalarf Value;
|
||||||
unsigned int Count;
|
unsigned int Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
BEGIN_TESTING(Math VoxImage Copy);
|
BEGIN_TESTING(Math VoxImage Copy);
|
||||||
|
|
||||||
{
|
{
|
||||||
VoxImage<TestVoxel> img(Vector3i(10,10,10));
|
VoxImage<TestVoxel> img(Vector3i(10, 10, 10));
|
||||||
TestVoxel zero = {0,0};
|
TestVoxel zero = {0.f, 0};
|
||||||
img.InitVoxels(zero);
|
img.InitVoxels(zero);
|
||||||
TestVoxel nonzero = {5.552368, 0};
|
TestVoxel nonzero = {5.552368f, 0};
|
||||||
img[Vector3i(5,1,7)] = nonzero;
|
img[Vector3i(5, 1, 7)] = nonzero;
|
||||||
img[img.Find(HPoint3f(3,3,3))].Value = 5.552369;
|
img[img.Find(HPoint3f(3, 3, 3))].Value = 5.552369;
|
||||||
TEST1( img.GetValue(Vector3i(5,1,7)) == 5.552368f );
|
TEST1(img.GetValue(Vector3i(5, 1, 7)) == 5.552368f);
|
||||||
|
|
||||||
|
img.SetOrigin(Vector3f(4, 5, 6));
|
||||||
|
|
||||||
img.SetOrigin(Vector3f(4,5,6));
|
std::cout << "\n";
|
||||||
|
|
||||||
std::cout << "\n";
|
img.PrintSelf(std::cout);
|
||||||
|
|
||||||
img.PrintSelf(std::cout);
|
VoxImage<TestVoxel> img2 = img;
|
||||||
|
img2.PrintSelf(std::cout);
|
||||||
|
|
||||||
VoxImage<TestVoxel> img2 = img;
|
TEST1(img.GetOrigin() == img2.GetOrigin());
|
||||||
img2.PrintSelf(std::cout);
|
TEST1(img.GetSpacing() == img2.GetSpacing());
|
||||||
|
|
||||||
TEST1( img.GetOrigin() == img2.GetOrigin() );
|
img2 = img;
|
||||||
TEST1( img.GetSpacing() == img2.GetSpacing() );
|
}
|
||||||
|
|
||||||
img2 = img;
|
std::cout << "returns " << _fail << "\n";
|
||||||
|
END_TESTING;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "returns " << _fail << "\n";
|
|
||||||
END_TESTING;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,99 +23,91 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "testing-prototype.h"
|
|
||||||
#include "Math/StructuredGrid.h"
|
|
||||||
#include "Math/VoxImage.h"
|
#include "Math/VoxImage.h"
|
||||||
|
#include "Math/StructuredGrid.h"
|
||||||
|
#include "testing-prototype.h"
|
||||||
|
|
||||||
using namespace uLib;
|
using namespace uLib;
|
||||||
|
|
||||||
|
|
||||||
struct TestVoxel {
|
struct TestVoxel {
|
||||||
Scalarf Value;
|
Scalarf Value;
|
||||||
unsigned int Count;
|
unsigned int Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
BEGIN_TESTING(Math StructuredGrid);
|
BEGIN_TESTING(Math StructuredGrid);
|
||||||
|
|
||||||
{ // SIMPLE TESTS //
|
{ // SIMPLE TESTS //
|
||||||
StructuredGrid img(Vector3i(10,10,10));
|
StructuredGrid img(Vector3i(10, 10, 10));
|
||||||
img.SetSpacing(Vector3f(3,3,3));
|
img.SetSpacing(Vector3f(3, 3, 3));
|
||||||
TEST1( img.GetWorldPoint(2,0,0) == HPoint3f(6,0,0) );
|
TEST1(img.GetWorldPoint(2, 0, 0) == HPoint3f(6, 0, 0));
|
||||||
TEST1( img.GetWorldPoint(1,1,1) == HPoint3f(3,3,3) );
|
TEST1(img.GetWorldPoint(1, 1, 1) == HPoint3f(3, 3, 3));
|
||||||
|
|
||||||
img.SetPosition(Vector3f(1,1,1));
|
img.SetPosition(Vector3f(1, 1, 1));
|
||||||
TEST1( img.GetWorldPoint(1,1,1) == HPoint3f(4,4,4) );
|
TEST1(img.GetWorldPoint(1, 1, 1) == HPoint3f(4, 4, 4));
|
||||||
TEST1( img.GetLocalPoint(4,4,4) == HPoint3f(1,1,1) );
|
TEST1(img.GetLocalPoint(4, 4, 4) == HPoint3f(1, 1, 1));
|
||||||
|
|
||||||
TEST0( img.IsInsideBounds(HPoint3f(5,33,-5)));
|
TEST0(img.IsInsideBounds(HPoint3f(5, 33, -5)));
|
||||||
TEST0( img.IsInsideBounds(HPoint3f(0,0,0)));
|
TEST0(img.IsInsideBounds(HPoint3f(0, 0, 0)));
|
||||||
TEST1( img.IsInsideBounds(HPoint3f(1,1,1)));
|
TEST1(img.IsInsideBounds(HPoint3f(1, 1, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // TEST WITH ORIGIN //
|
{ // TEST WITH ORIGIN //
|
||||||
StructuredGrid img(Vector3i(10,10,10));
|
StructuredGrid img(Vector3i(10, 10, 10));
|
||||||
img.SetSpacing(Vector3f(3,3,3));
|
img.SetSpacing(Vector3f(3, 3, 3));
|
||||||
img.SetOrigin(Vector3f(-1,1,-1));
|
img.SetOrigin(Vector3f(-1, 1, -1));
|
||||||
img.SetPosition(Vector3f(1,1,1));
|
img.SetPosition(Vector3f(1, 1, 1));
|
||||||
TEST1( img.GetWorldPoint(1,1,1) == HPoint3f(3,5,3) );
|
TEST1(img.GetWorldPoint(1, 1, 1) == HPoint3f(3, 5, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VoxImage<TestVoxel> img(Vector3i(10, 10, 10));
|
||||||
|
TestVoxel zero = {0.f, 0};
|
||||||
|
img.InitVoxels(zero);
|
||||||
|
TestVoxel nonzero = {5.552368f, 0};
|
||||||
|
img[Vector3i(5, 1, 7)] = nonzero;
|
||||||
|
img[img.Find(HPoint3f(3, 3, 3))].Value = 5.552369;
|
||||||
|
img.ExportToVtk("./test_vox_image.vtk", 0);
|
||||||
|
img.ExportToVtkXml("./test_vox_image.vti", 0);
|
||||||
|
TEST1(img.GetValue(Vector3i(5, 1, 7)) == 5.552368f);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
VoxImage<TestVoxel> img(Vector3i(10,10,10));
|
VoxImage<TestVoxel> img(Vector3i(4, 4, 4));
|
||||||
TestVoxel zero = {0,0};
|
TestVoxel zero = {0.f, 0};
|
||||||
img.InitVoxels(zero);
|
img.InitVoxels(zero);
|
||||||
TestVoxel nonzero = {5.552368, 0};
|
img.SetSpacing(Vector3f(2, 2, 2));
|
||||||
img[Vector3i(5,1,7)] = nonzero;
|
img.SetPosition(Vector3f(-4, -4, -4));
|
||||||
img[img.Find(HPoint3f(3,3,3))].Value = 5.552369;
|
TEST1(img.GetWorldPoint(img.GetLocalPoint(HPoint3f(5, 5, 5))) ==
|
||||||
img.ExportToVtk("./test_vox_image.vtk",0);
|
HPoint3f(5, 5, 5));
|
||||||
img.ExportToVtkXml("./test_vox_image.vti",0);
|
}
|
||||||
TEST1( img.GetValue(Vector3i(5,1,7)) == 5.552368f );
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
VoxImage<TestVoxel> img(Vector3i(4,4,4));
|
VoxImage<TestVoxel> imgR(Vector3i(0, 0, 0));
|
||||||
TestVoxel zero = {0,0};
|
imgR.ImportFromVtk("./test_vox_image.vtk");
|
||||||
img.InitVoxels(zero);
|
imgR.ExportToVtk("./read_and_saved.vtk");
|
||||||
img.SetSpacing(Vector3f(2,2,2));
|
}
|
||||||
img.SetPosition(Vector3f(-4,-4,-4));
|
|
||||||
TEST1( img.GetWorldPoint(img.GetLocalPoint(HPoint3f(5,5,5))) == HPoint3f(5,5,5));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
VoxImage<TestVoxel> imgR(Vector3i(0,0,0));
|
VoxImage<TestVoxel> img(Vector3i(4, 4, 4));
|
||||||
imgR.ImportFromVtk("./test_vox_image.vtk");
|
img.InitVoxels({0.f, 0});
|
||||||
imgR.ExportToVtk("./read_and_saved.vtk");
|
for (int i = 0; i < 4; i++) {
|
||||||
}
|
for (int j = 0; j < 4; j++) {
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
{
|
img[Vector3i(i, j, k)] = {static_cast<float>(i + j + k), 0};
|
||||||
VoxImage<TestVoxel> img(Vector3i(4,4,4));
|
|
||||||
img.InitVoxels({0,0});
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
for (int j=0; j<4; j++) {
|
|
||||||
for (int k=0; k<4; k++) {
|
|
||||||
img[Vector3i(i,j,k)] = {i+j+k,0};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
img.ExportToVti("./vti_saved.vti",0,1);
|
}
|
||||||
// img.ImportFromVtkXml("./test_vox_image.vti");
|
|
||||||
}
|
}
|
||||||
|
img.ExportToVti("./vti_saved.vti", 0, 1);
|
||||||
|
// img.ImportFromVtkXml("./test_vox_image.vti");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VoxImage<TestVoxel> img1(Vector3i(5, 5, 5));
|
||||||
|
VoxImage<TestVoxel> img2;
|
||||||
|
img2 = img1;
|
||||||
|
TEST1(img1.GetDims() == img2.GetDims());
|
||||||
|
}
|
||||||
|
|
||||||
{
|
END_TESTING
|
||||||
VoxImage<TestVoxel> img1(Vector3i(5,5,5));
|
|
||||||
VoxImage<TestVoxel> img2;
|
|
||||||
img2 = img1;
|
|
||||||
TEST1( img1.GetDims() == img2.GetDims() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
END_TESTING
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ int Vector4f0(Vector4f c) {
|
|||||||
|
|
||||||
typedef VoxRaytracer Raytracer;
|
typedef VoxRaytracer Raytracer;
|
||||||
|
|
||||||
|
struct TestVoxel {
|
||||||
|
float Value;
|
||||||
|
int Count;
|
||||||
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
BEGIN_TESTING(Math VoxRaytracer);
|
BEGIN_TESTING(Math VoxRaytracer);
|
||||||
|
|
||||||
@@ -132,5 +137,41 @@ int main() {
|
|||||||
ray.PrintSelf(std::cout);
|
ray.PrintSelf(std::cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_CUDA
|
||||||
|
{
|
||||||
|
std::cout << "\n--- Testing CUDA Raytracer Accumulator ---\n";
|
||||||
|
|
||||||
|
VoxImage<TestVoxel> img_cuda(Vector3i(4, 4, 4));
|
||||||
|
img_cuda.SetSpacing(Vector3f(2, 2, 2));
|
||||||
|
img_cuda.SetPosition(Vector3f(-4, -4, -4));
|
||||||
|
|
||||||
|
Raytracer ray(img_cuda);
|
||||||
|
|
||||||
|
HLine3f line1;
|
||||||
|
line1.origin << -3, -3, -3, 1;
|
||||||
|
line1.direction << 1, 1, 1, 0;
|
||||||
|
|
||||||
|
HLine3f line2;
|
||||||
|
line2.origin << -3, -3, 1, 1;
|
||||||
|
line2.direction << 1, 1, -1, 0;
|
||||||
|
|
||||||
|
HLine3f lines[2] = {line1, line2};
|
||||||
|
// Execute CUDA kernel wrapper over target VoxImage mapped internally into
|
||||||
|
// VRAM
|
||||||
|
ray.AccumulateLinesCUDA(lines, 2, img_cuda);
|
||||||
|
|
||||||
|
// Validate device synchronization returned data correctly pulling back to
|
||||||
|
// host
|
||||||
|
TEST1(img_cuda.Data().GetDevice() !=
|
||||||
|
MemoryDevice::RAM); // Confirms VRAM executed
|
||||||
|
|
||||||
|
// Pull down checking values
|
||||||
|
float l_val = img_cuda[img_cuda.Find(Vector4f(-3, -3, -3, 1))].Value;
|
||||||
|
std::cout << "Accumulated Voxel test trace point length returned: " << l_val
|
||||||
|
<< "\n";
|
||||||
|
TEST1(l_val > 0.1f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
END_TESTING
|
END_TESTING
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# TESTS
|
# TESTS
|
||||||
set( TESTS
|
set( TESTS
|
||||||
RootDebugTest
|
# RootDebugTest
|
||||||
muBlastMCTrackTest
|
# muBlastMCTrackTest
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBRARIES
|
set(LIBRARIES
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ set( TESTS
|
|||||||
vtkMuonScatter
|
vtkMuonScatter
|
||||||
vtkStructuredGridTest
|
vtkStructuredGridTest
|
||||||
vtkVoxRaytracerTest
|
vtkVoxRaytracerTest
|
||||||
vtkVoxImageTest
|
# vtkVoxImageTest
|
||||||
# vtkTriangleMeshTest
|
# vtkTriangleMeshTest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user