mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
updated Atomic array to use new excution object paradigm
This commit is contained in:
parent
6bc579e461
commit
3c9e7f049f
@ -53,7 +53,8 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>,
|
||||
Device>
|
||||
{
|
||||
using ExecObjectType = vtkm::exec::AtomicArray<T, Device>;
|
||||
using ExecObjectType = vtkm::exec::AtomicArrayExecutionObject<T, Device>;
|
||||
using ExecType = vtkm::exec::AtomicArray<T>;
|
||||
|
||||
template <typename InputDomainType>
|
||||
VTKM_CONT ExecObjectType operator()(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> array,
|
||||
@ -64,8 +65,8 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
|
||||
// Note: we ignore the size of the domain because the randomly accessed
|
||||
// array might not have the same size depending on how the user is using
|
||||
// the array.
|
||||
|
||||
return ExecObjectType(array);
|
||||
ExecType obj = ExecType(array);
|
||||
return obj.PrepareForExecution(Device());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -113,31 +113,23 @@ public:
|
||||
IdPortalType OutputArray;
|
||||
};
|
||||
|
||||
template <typename PortalType>
|
||||
struct GenericClearArrayKernel
|
||||
struct ClearArrayKernel
|
||||
{
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
|
||||
VTKM_CONT
|
||||
GenericClearArrayKernel(const PortalType& array,
|
||||
const ValueType& fillValue = static_cast<ValueType>(OFFSET))
|
||||
ClearArrayKernel(const IdPortalType& array)
|
||||
: Array(array)
|
||||
, Dims()
|
||||
, FillValue(fillValue)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
GenericClearArrayKernel(const PortalType& array,
|
||||
const vtkm::Id3& dims,
|
||||
const ValueType& fillValue = static_cast<ValueType>(OFFSET))
|
||||
ClearArrayKernel(const IdPortalType& array, const vtkm::Id3& dims)
|
||||
: Array(array)
|
||||
, Dims(dims)
|
||||
, FillValue(fillValue)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC void operator()(vtkm::Id index) const { this->Array.Set(index, this->FillValue); }
|
||||
VTKM_EXEC void operator()(vtkm::Id index) const { this->Array.Set(index, OFFSET); }
|
||||
|
||||
VTKM_EXEC void operator()(vtkm::Id3 index) const
|
||||
{
|
||||
@ -148,13 +140,10 @@ public:
|
||||
|
||||
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
|
||||
|
||||
PortalType Array;
|
||||
IdPortalType Array;
|
||||
vtkm::Id3 Dims;
|
||||
ValueType FillValue;
|
||||
};
|
||||
|
||||
using ClearArrayKernel = GenericClearArrayKernel<IdPortalType>;
|
||||
|
||||
struct ClearArrayMapKernel //: public vtkm::exec::WorkletMapField
|
||||
{
|
||||
|
||||
@ -202,57 +191,6 @@ public:
|
||||
vtkm::Id3 Dims;
|
||||
};
|
||||
|
||||
// Checks that each instance is only visited once:
|
||||
struct OverlapKernel
|
||||
{
|
||||
using ArrayType = ArrayHandle<bool>;
|
||||
using PortalType = typename ArrayType::template ExecutionTypes<DeviceAdapterTag>::Portal;
|
||||
|
||||
PortalType TrackerPortal;
|
||||
PortalType ValidPortal;
|
||||
vtkm::Id3 Dims;
|
||||
|
||||
VTKM_CONT
|
||||
OverlapKernel(const PortalType& trackerPortal,
|
||||
const PortalType& validPortal,
|
||||
const vtkm::Id3& dims)
|
||||
: TrackerPortal(trackerPortal)
|
||||
, ValidPortal(validPortal)
|
||||
, Dims(dims)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
OverlapKernel(const PortalType& trackerPortal, const PortalType& validPortal)
|
||||
: TrackerPortal(trackerPortal)
|
||||
, ValidPortal(validPortal)
|
||||
, Dims()
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC void operator()(vtkm::Id index) const
|
||||
{
|
||||
if (this->TrackerPortal.Get(index))
|
||||
{ // this index has already been visited, that's an error
|
||||
this->ValidPortal.Set(index, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->TrackerPortal.Set(index, true);
|
||||
this->ValidPortal.Set(index, true);
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_EXEC void operator()(vtkm::Id3 index) const
|
||||
{
|
||||
//convert from id3 to id
|
||||
vtkm::Id flatIndex = index[0] + this->Dims[0] * (index[1] + this->Dims[1] * index[2]);
|
||||
this->operator()(flatIndex);
|
||||
}
|
||||
|
||||
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
|
||||
};
|
||||
|
||||
struct OneErrorKernel
|
||||
{
|
||||
VTKM_EXEC void operator()(vtkm::Id index) const
|
||||
@ -332,8 +270,8 @@ public:
|
||||
struct AtomicKernel
|
||||
{
|
||||
VTKM_CONT
|
||||
AtomicKernel(const vtkm::exec::AtomicArray<T, DeviceAdapterTag>& array)
|
||||
: AArray(array)
|
||||
AtomicKernel(const vtkm::exec::AtomicArray<T>& array)
|
||||
: AArray(array.PrepareForExecution(DeviceAdapterTag()))
|
||||
{
|
||||
}
|
||||
|
||||
@ -345,15 +283,15 @@ public:
|
||||
|
||||
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
|
||||
|
||||
vtkm::exec::AtomicArray<T, DeviceAdapterTag> AArray;
|
||||
vtkm::exec::AtomicArrayExecutionObject<T, DeviceAdapterTag> AArray;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct AtomicCASKernel
|
||||
{
|
||||
VTKM_CONT
|
||||
AtomicCASKernel(const vtkm::exec::AtomicArray<T, DeviceAdapterTag>& array)
|
||||
: AArray(array)
|
||||
AtomicCASKernel(const vtkm::exec::AtomicArray<T>& array)
|
||||
: AArray(array.PrepareForExecution(DeviceAdapterTag()))
|
||||
{
|
||||
}
|
||||
|
||||
@ -374,7 +312,7 @@ public:
|
||||
|
||||
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
|
||||
|
||||
vtkm::exec::AtomicArray<T, DeviceAdapterTag> AArray;
|
||||
vtkm::exec::AtomicArrayExecutionObject<T, DeviceAdapterTag> AArray;
|
||||
};
|
||||
|
||||
class VirtualObjectTransferKernel
|
||||
@ -704,78 +642,6 @@ private:
|
||||
VTKM_TEST_ASSERT(value == index + OFFSET, "Got bad value for scheduled vtkm::Id3 kernels.");
|
||||
}
|
||||
} //release memory
|
||||
|
||||
// Ensure that each element is only visited once:
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing Schedule for overlap" << std::endl;
|
||||
|
||||
{
|
||||
using BoolArray = ArrayHandle<bool>;
|
||||
using BoolPortal = typename BoolArray::template ExecutionTypes<DeviceAdapterTag>::Portal;
|
||||
BoolArray tracker;
|
||||
BoolArray valid;
|
||||
|
||||
// Initialize tracker with 'false' values
|
||||
std::cout << "Allocating and initializing memory" << std::endl;
|
||||
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
|
||||
tracker.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag()), false),
|
||||
ARRAY_SIZE);
|
||||
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
|
||||
valid.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag()), false),
|
||||
ARRAY_SIZE);
|
||||
|
||||
std::cout << "Running Overlap kernel." << std::endl;
|
||||
Algorithm::Schedule(OverlapKernel(tracker.PrepareForInPlace(DeviceAdapterTag()),
|
||||
valid.PrepareForInPlace(DeviceAdapterTag())),
|
||||
ARRAY_SIZE);
|
||||
|
||||
std::cout << "Checking results." << std::endl;
|
||||
|
||||
auto vPortal = valid.GetPortalConstControl();
|
||||
for (vtkm::Id i = 0; i < ARRAY_SIZE; i++)
|
||||
{
|
||||
bool isValid = vPortal.Get(i);
|
||||
VTKM_TEST_ASSERT(isValid, "Schedule executed some elements more than once.");
|
||||
}
|
||||
} // release memory
|
||||
|
||||
// Ensure that each element is only visited once:
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing Schedule for overlap with vtkm::Id3" << std::endl;
|
||||
|
||||
{
|
||||
static constexpr vtkm::Id numElems{ DIM_SIZE * DIM_SIZE * DIM_SIZE };
|
||||
static const vtkm::Id3 dims{ DIM_SIZE, DIM_SIZE, DIM_SIZE };
|
||||
|
||||
using BoolArray = ArrayHandle<bool>;
|
||||
using BoolPortal = typename BoolArray::template ExecutionTypes<DeviceAdapterTag>::Portal;
|
||||
BoolArray tracker;
|
||||
BoolArray valid;
|
||||
|
||||
// Initialize tracker with 'false' values
|
||||
std::cout << "Allocating and initializing memory" << std::endl;
|
||||
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
|
||||
tracker.PrepareForOutput(numElems, DeviceAdapterTag()), dims, false),
|
||||
numElems);
|
||||
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
|
||||
valid.PrepareForOutput(numElems, DeviceAdapterTag()), dims, false),
|
||||
numElems);
|
||||
|
||||
std::cout << "Running Overlap kernel." << std::endl;
|
||||
Algorithm::Schedule(OverlapKernel(tracker.PrepareForInPlace(DeviceAdapterTag()),
|
||||
valid.PrepareForInPlace(DeviceAdapterTag()),
|
||||
dims),
|
||||
dims);
|
||||
|
||||
std::cout << "Checking results." << std::endl;
|
||||
|
||||
auto vPortal = valid.GetPortalConstControl();
|
||||
for (vtkm::Id i = 0; i < numElems; i++)
|
||||
{
|
||||
bool isValid = vPortal.Get(i);
|
||||
VTKM_TEST_ASSERT(isValid, "Id3 Schedule executed some elements more than once.");
|
||||
}
|
||||
} // release memory
|
||||
}
|
||||
|
||||
static VTKM_CONT void TestCopyIf()
|
||||
@ -2228,7 +2094,7 @@ private:
|
||||
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement =
|
||||
vtkm::cont::make_ArrayHandle(singleElement);
|
||||
|
||||
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
|
||||
vtkm::exec::AtomicArray<vtkm::Int32> atomic(atomicElement);
|
||||
Algorithm::Schedule(AtomicKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
|
||||
vtkm::Int32 expected = vtkm::Int32(atomicCount);
|
||||
vtkm::Int32 actual = atomicElement.GetPortalControl().Get(0);
|
||||
@ -2242,7 +2108,7 @@ private:
|
||||
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement =
|
||||
vtkm::cont::make_ArrayHandle(singleElement);
|
||||
|
||||
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
|
||||
vtkm::exec::AtomicArray<vtkm::Int64> atomic(atomicElement);
|
||||
Algorithm::Schedule(AtomicKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
|
||||
vtkm::Int64 expected = vtkm::Int64(atomicCount);
|
||||
vtkm::Int64 actual = atomicElement.GetPortalControl().Get(0);
|
||||
@ -2256,7 +2122,7 @@ private:
|
||||
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement =
|
||||
vtkm::cont::make_ArrayHandle(singleElement);
|
||||
|
||||
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
|
||||
vtkm::exec::AtomicArray<vtkm::Int32> atomic(atomicElement);
|
||||
Algorithm::Schedule(AtomicCASKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
|
||||
vtkm::Int32 expected = vtkm::Int32(atomicCount);
|
||||
vtkm::Int32 actual = atomicElement.GetPortalControl().Get(0);
|
||||
@ -2270,7 +2136,7 @@ private:
|
||||
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement =
|
||||
vtkm::cont::make_ArrayHandle(singleElement);
|
||||
|
||||
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
|
||||
vtkm::exec::AtomicArray<vtkm::Int64> atomic(atomicElement);
|
||||
Algorithm::Schedule(AtomicCASKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
|
||||
vtkm::Int64 expected = vtkm::Int64(atomicCount);
|
||||
vtkm::Int64 actual = atomicElement.GetPortalControl().Get(0);
|
||||
|
@ -36,34 +36,20 @@ struct AtomicArrayTypeListTag : vtkm::ListTagBase<vtkm::Int32, vtkm::Int64>
|
||||
{
|
||||
};
|
||||
|
||||
/// A class that can be used to atomically operate on an array of values safely
|
||||
/// across multiple instances of the same worklet. This is useful when you have
|
||||
/// an algorithm that needs to accumulate values in parallel, but writing out a
|
||||
/// value per worklet might be memory prohibitive.
|
||||
///
|
||||
/// To construct an AtomicArray you will need to pass in an
|
||||
/// vtkm::cont::ArrayHandle that is used as the underlying storage for the
|
||||
/// AtomicArray
|
||||
///
|
||||
/// Supported Operations: add / compare and swap (CAS)
|
||||
///
|
||||
/// Supported Types: 32 / 64 bit signed integers
|
||||
///
|
||||
///
|
||||
template <typename T, typename DeviceAdapterTag>
|
||||
class AtomicArray : public vtkm::cont::ExecutionObjectBase
|
||||
template <typename T, typename Device>
|
||||
class AtomicArrayExecutionObject
|
||||
{
|
||||
public:
|
||||
using ValueType = T;
|
||||
|
||||
VTKM_CONT
|
||||
AtomicArray()
|
||||
AtomicArrayExecutionObject()
|
||||
: AtomicImplementation((vtkm::cont::ArrayHandle<T>()))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename StorageType>
|
||||
VTKM_CONT AtomicArray(vtkm::cont::ArrayHandle<T, StorageType> handle)
|
||||
VTKM_CONT AtomicArrayExecutionObject(vtkm::cont::ArrayHandle<T, StorageType> handle)
|
||||
: AtomicImplementation(handle)
|
||||
{
|
||||
}
|
||||
@ -88,7 +74,59 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
vtkm::cont::DeviceAdapterAtomicArrayImplementation<T, DeviceAdapterTag> AtomicImplementation;
|
||||
vtkm::cont::DeviceAdapterAtomicArrayImplementation<T, Device> AtomicImplementation;
|
||||
};
|
||||
|
||||
/// A class that can be used to atomically operate on an array of values safely
|
||||
/// across multiple instances of the same worklet. This is useful when you have
|
||||
/// an algorithm that needs to accumulate values in parallel, but writing out a
|
||||
/// value per worklet might be memory prohibitive.
|
||||
///
|
||||
/// To construct an AtomicArray you will need to pass in an
|
||||
/// vtkm::cont::ArrayHandle that is used as the underlying storage for the
|
||||
/// AtomicArray
|
||||
///
|
||||
/// Supported Operations: add / compare and swap (CAS)
|
||||
///
|
||||
/// Supported Types: 32 / 64 bit signed integers
|
||||
///
|
||||
///
|
||||
template <typename T>
|
||||
class AtomicArray : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
using ValueType = T;
|
||||
|
||||
template <typename Device>
|
||||
VTKM_CONT AtomicArrayExecutionObject<T, Device> PrepareForExecution(Device) const
|
||||
{
|
||||
AtomicArrayExecutionObject<T, Device> execObject;
|
||||
if (isHandle)
|
||||
{
|
||||
execObject = AtomicArrayExecutionObject<T, Device>(this->Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
execObject = AtomicArrayExecutionObject<T, Device>();
|
||||
}
|
||||
return execObject;
|
||||
}
|
||||
VTKM_CONT
|
||||
AtomicArray()
|
||||
: isHandle(false)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename StorageType>
|
||||
VTKM_CONT AtomicArray(vtkm::cont::ArrayHandle<T, StorageType> handle)
|
||||
: isHandle(true)
|
||||
, Handle(handle)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
bool isHandle;
|
||||
vtkm::cont::ArrayHandle<T> Handle;
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::exec
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/Math.h>
|
||||
#include <vtkm/Swap.h>
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VectorAnalysis.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
@ -158,7 +157,9 @@ template <typename DeviceTag>
|
||||
class EdgePlotter : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using AtomicPackedFrameBufferHandle = vtkm::exec::AtomicArray<vtkm::Int64, DeviceTag>;
|
||||
using AtomicPackedFrameBufferHandle =
|
||||
vtkm::exec::AtomicArrayExecutionObject<vtkm::Int64, DeviceTag>;
|
||||
using AtomicPackedFrameBuffer = vtkm::exec::AtomicArray<vtkm::Int64>;
|
||||
|
||||
using ControlSignature = void(FieldIn<Id2Type>, WholeArrayIn<Vec3>, WholeArrayIn<Scalar>);
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
@ -175,7 +176,7 @@ public:
|
||||
bool assocPoints,
|
||||
const vtkm::Range& fieldRange,
|
||||
const ColorMapHandle& colorMap,
|
||||
const AtomicPackedFrameBufferHandle& frameBuffer,
|
||||
const AtomicPackedFrameBuffer& frameBuffer,
|
||||
const vtkm::Range& clippingRange)
|
||||
: WorldToProjection(worldToProjection)
|
||||
, Width(width)
|
||||
@ -187,7 +188,7 @@ public:
|
||||
, AssocPoints(assocPoints)
|
||||
, ColorMap(colorMap.PrepareForInput(DeviceTag()))
|
||||
, ColorMapSize(vtkm::Float32(colorMap.GetNumberOfValues() - 1))
|
||||
, FrameBuffer(frameBuffer)
|
||||
, FrameBuffer(frameBuffer.PrepareForExecution(DeviceTag()))
|
||||
, FieldMin(vtkm::Float32(fieldRange.Min))
|
||||
{
|
||||
InverseFieldDelta = 1.0f / vtkm::Float32(fieldRange.Length());
|
||||
@ -220,16 +221,16 @@ public:
|
||||
bool transposed = vtkm::Abs(y2 - y1) > vtkm::Abs(x2 - x1);
|
||||
if (transposed)
|
||||
{
|
||||
vtkm::Swap(x1, y1);
|
||||
vtkm::Swap(x2, y2);
|
||||
std::swap(x1, y1);
|
||||
std::swap(x2, y2);
|
||||
}
|
||||
|
||||
// Ensure we are always going from left to right
|
||||
if (x1 > x2)
|
||||
{
|
||||
vtkm::Swap(x1, x2);
|
||||
vtkm::Swap(y1, y2);
|
||||
vtkm::Swap(z1, z2);
|
||||
std::swap(x1, x2);
|
||||
std::swap(y1, y2);
|
||||
std::swap(z1, z2);
|
||||
}
|
||||
|
||||
vtkm::Float32 dx = x2 - x1;
|
||||
|
@ -297,7 +297,7 @@ private:
|
||||
vtkm::Int32 LeafCount;
|
||||
//Int8Handle Counters;
|
||||
//Int8ArrayPortal CountersPortal;
|
||||
vtkm::exec::AtomicArray<vtkm::Int32, Device> Counters;
|
||||
vtkm::exec::AtomicArrayExecutionObject<vtkm::Int32, Device> Counters;
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
@ -306,12 +306,12 @@ public:
|
||||
IdArrayHandle& rightChildren,
|
||||
vtkm::Int32 leafCount,
|
||||
Float4ArrayHandle flatBVH,
|
||||
const vtkm::exec::AtomicArray<vtkm::Int32, Device>& counters)
|
||||
const vtkm::exec::AtomicArray<vtkm::Int32>& counters)
|
||||
: Parents(parents.PrepareForInput(Device()))
|
||||
, LeftChildren(leftChildren.PrepareForInput(Device()))
|
||||
, RightChildren(rightChildren.PrepareForInput(Device()))
|
||||
, LeafCount(leafCount)
|
||||
, Counters(counters)
|
||||
, Counters(counters.PrepareForExecution(Device()))
|
||||
|
||||
{
|
||||
this->FlatBVH = flatBVH.PrepareForOutput((LeafCount - 1) * 4, Device());
|
||||
@ -774,7 +774,7 @@ VTKM_CONT void LinearBVHBuilder::RunOnDevice(LinearBVH& linearBVH, Device device
|
||||
vtkm::Int32 zero = 0;
|
||||
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Int32>, Device>(MemSet<vtkm::Int32>(zero))
|
||||
.Invoke(counters);
|
||||
vtkm::exec::AtomicArray<vtkm::Int32, Device> atomicCounters(counters);
|
||||
vtkm::exec::AtomicArray<vtkm::Int32> atomicCounters(counters);
|
||||
|
||||
|
||||
vtkm::worklet::DispatcherMapField<PropagateAABBs<Device>, Device>(
|
||||
@ -905,10 +905,6 @@ template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<
|
||||
template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagTBB>(
|
||||
vtkm::cont::DeviceAdapterTagTBB);
|
||||
#endif
|
||||
#ifdef VTKM_ENABLE_OPENMP
|
||||
template VTKM_CONT_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagOpenMP>(
|
||||
vtkm::cont::DeviceAdapterTagOpenMP);
|
||||
#endif
|
||||
#ifdef VTKM_ENABLE_CUDA
|
||||
template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagCuda>(
|
||||
vtkm::cont::DeviceAdapterTagCuda);
|
||||
|
Loading…
Reference in New Issue
Block a user