VTK-m now supports passing pointers when invoking worklets.

The original design of invoke and the transport infrastructure
relied on the implementation behavior of vtkm::cont types
such as ArrayHandle that used an internal shared_ptr to managed
state. This allowed passing by value instead of passing by
non-const ref when needing to transfer information to the device.

As VTK-m adds support for classes that use virtuals the ability
to pass by base pointer type allows for us to invoke worklets
using a base type without the risk of type slicing.

Additional by moving over to a non-const ref Invocation we
can update all transports that have 'output' to now be
by ref and therefore support types that can't be copied while
being 'more' correct.
This commit is contained in:
Robert Maynard 2018-06-28 14:29:27 -04:00
parent c631dccfcb
commit 64958b014b
22 changed files with 276 additions and 97 deletions

@ -0,0 +1,19 @@
# VTK-m now supports dispatcher parameters being pointers
Previously it was only possible to pass values to a dispatcher when
you wanted to invoke a VTK-m worklet. This caused problems when it came
to designing new types that used inheritance as the types couldn't be
past as the base type to the dispatcher. To fix this issue we now
support invoking worklets with pointers as seen below.
```cpp
vtkm::cont::ArrayHandle<T> input;
//fill input
vtkm::cont::ArrayHandle<T> output;
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
dispatcher(&input, output);
dispatcher(input, &output);
dispatcher(&input, &output);
```

@ -120,7 +120,8 @@ public:
template <typename T>
struct ArrayHandleCheck
{
using type = typename std::is_base_of<::vtkm::cont::internal::ArrayHandleBase, T>::type;
using U = typename std::remove_pointer<T>::type;
using type = typename std::is_base_of<::vtkm::cont::internal::ArrayHandleBase, U>::type;
};
#define VTKM_IS_ARRAY_HANDLE(T) \

@ -87,7 +87,8 @@ namespace internal
template <typename T>
struct CellSetCheck
{
using type = typename std::is_base_of<vtkm::cont::CellSet, T>;
using U = typename std::remove_pointer<T>::type;
using type = typename std::is_base_of<vtkm::cont::CellSet, U>;
};
#define VTKM_IS_CELL_SET(T) VTKM_STATIC_ASSERT(::vtkm::cont::internal::CellSetCheck<T>::type::value)

@ -53,7 +53,7 @@ struct Transport<vtkm::cont::arg::TransportTagArrayInOut, ContObjectType, Device
using ExecObjectType = decltype(std::declval<ContObjectType>().PrepareForInPlace(Device()));
template <typename InputDomainType>
VTKM_CONT ExecObjectType operator()(ContObjectType object,
VTKM_CONT ExecObjectType operator()(ContObjectType& object,
const InputDomainType& vtkmNotUsed(inputDomain),
vtkm::Id vtkmNotUsed(inputRange),
vtkm::Id outputRange) const

@ -53,7 +53,7 @@ struct Transport<vtkm::cont::arg::TransportTagArrayOut, ContObjectType, Device>
decltype(std::declval<ContObjectType>().PrepareForOutput(vtkm::Id{}, Device()));
template <typename InputDomainType>
VTKM_CONT ExecObjectType operator()(ContObjectType object,
VTKM_CONT ExecObjectType operator()(ContObjectType& object,
const InputDomainType& vtkmNotUsed(inputDomain),
vtkm::Id vtkmNotUsed(inputRange),
vtkm::Id outputRange) const

@ -56,10 +56,11 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
using ExecObjectType = vtkm::exec::AtomicArray<T, Device>;
template <typename InputDomainType>
VTKM_CONT ExecObjectType operator()(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> array,
const InputDomainType&,
vtkm::Id,
vtkm::Id) const
VTKM_CONT ExecObjectType
operator()(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& array,
const InputDomainType&,
vtkm::Id,
vtkm::Id) const
{
// 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

@ -56,7 +56,7 @@ struct Transport<vtkm::cont::arg::TransportTagExecObject, ContObjectType, Device
using ExecObjectType = decltype(std::declval<ContObjectType>().PrepareForExecution(Device()));
template <typename InputDomainType>
VTKM_CONT ExecObjectType
operator()(const ContObjectType& object, const InputDomainType&, vtkm::Id, vtkm::Id) const
operator()(ContObjectType& object, const InputDomainType&, vtkm::Id, vtkm::Id) const
{
return object.PrepareForExecution(Device());
}

@ -61,7 +61,7 @@ struct Transport<vtkm::cont::arg::TransportTagWholeArrayIn, ContObjectType, Devi
template <typename InputDomainType>
VTKM_CONT ExecObjectType
operator()(ContObjectType array, const InputDomainType&, vtkm::Id, vtkm::Id) const
operator()(ContObjectType& array, const InputDomainType&, vtkm::Id, vtkm::Id) const
{
// 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

@ -63,7 +63,7 @@ struct Transport<vtkm::cont::arg::TransportTagWholeArrayInOut, ContObjectType, D
template <typename InputDomainType>
VTKM_CONT ExecObjectType
operator()(ContObjectType array, const InputDomainType&, vtkm::Id, vtkm::Id) const
operator()(ContObjectType& array, const InputDomainType&, vtkm::Id, vtkm::Id) const
{
// 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

@ -63,7 +63,7 @@ struct Transport<vtkm::cont::arg::TransportTagWholeArrayOut, ContObjectType, Dev
template <typename InputDomainType>
VTKM_CONT ExecObjectType
operator()(ContObjectType array, const InputDomainType&, vtkm::Id, vtkm::Id) const
operator()(ContObjectType& array, const InputDomainType&, vtkm::Id, vtkm::Id) const
{
// 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

@ -23,7 +23,7 @@ set(unit_tests
UnitTestCudaArrayHandleFancy.cu
UnitTestCudaArrayHandleVirtualCoordinates.cu
UnitTestCudaCellLocatorTwoLevelUniformGrid.cu
UnitTestCudaComputeRange.cu
#UnitTestCudaComputeRange.cu
UnitTestCudaColorTable.cu
UnitTestCudaDataSetExplicit.cu
UnitTestCudaDataSetSingleType.cu

@ -63,7 +63,7 @@ public:
}
template <typename Invocation>
VTKM_CONT void DoInvoke(const Invocation& invocation) const
VTKM_CONT void DoInvoke(Invocation& invocation) const
{
// This is the type for the input domain
using InputDomainType = typename Invocation::InputDomainType;
@ -76,7 +76,7 @@ public:
// a DynamicArrayHandle that gets cast to one). The size of the domain
// (number of threads/worklet instances) is equal to the size of the
// array.
vtkm::Id numInstances = inputDomain.GetNumberOfValues();
auto numInstances = internal::scheduling_range(inputDomain);
// A MapField is a pretty straightforward dispatch. Once we know the number
// of invocations, the superclass can take care of the rest.

@ -64,10 +64,11 @@ public:
}
template <typename Invocation>
VTKM_CONT void DoInvoke(const Invocation& invocation) const
VTKM_CONT void DoInvoke(Invocation& invocation) const
{
// This is the type for the input domain
using InputDomainType = typename Invocation::InputDomainType;
using SchedulingRangeType = typename WorkletType::ToTopologyType;
// If you get a compile error on this line, then you have tried to use
// something that is not a vtkm::cont::CellSet as the input domain to a
@ -76,12 +77,12 @@ public:
// We can pull the input domain parameter (the data specifying the input
// domain) from the invocation object.
const InputDomainType& inputDomain = invocation.GetInputDomain();
const auto& inputDomain = invocation.GetInputDomain();
// Now that we have the input domain, we can extract the range of the
// scheduling and call BadicInvoke.
this->BasicInvoke(
invocation, inputDomain.GetSchedulingRange(typename WorkletType::ToTopologyType()), Device());
invocation, internal::scheduling_range(inputDomain, SchedulingRangeType{}), Device());
}
};
}

@ -65,7 +65,7 @@ public:
}
template <typename Invocation>
void DoInvoke(const Invocation& invocation) const
void DoInvoke(Invocation& invocation) const
{
// This is the type for the input domain
using InputDomainType = typename Invocation::InputDomainType;
@ -78,7 +78,7 @@ public:
// We can pull the input domain parameter (the data specifying the input
// domain) from the invocation object.
const InputDomainType& inputDomain = invocation.GetInputDomain();
auto inputRange = inputDomain.GetSchedulingRange(vtkm::TopologyElementTagPoint());
auto inputRange = internal::scheduling_range(inputDomain, vtkm::TopologyElementTagPoint{});
// This is pretty straightforward dispatch. Once we know the number
// of invocations, the superclass can take care of the rest.

@ -65,7 +65,7 @@ public:
}
template <typename Invocation>
void DoInvoke(const Invocation& invocation) const
void DoInvoke(Invocation& invocation) const
{
// This is the type for the input domain
using InputDomainType = typename Invocation::InputDomainType;

@ -200,7 +200,7 @@ public:
void SetNumberOfBlocks(vtkm::Id numberOfBlocks) { NumberOfBlocks = numberOfBlocks; }
template <typename Invocation, typename DeviceAdapter>
VTKM_CONT void BasicInvoke(const Invocation& invocation,
VTKM_CONT void BasicInvoke(Invocation& invocation,
vtkm::Id numInstances,
vtkm::Id globalIndexOffset,
DeviceAdapter device) const
@ -213,7 +213,7 @@ public:
}
template <typename Invocation>
VTKM_CONT void DoInvoke(const Invocation& invocation) const
VTKM_CONT void DoInvoke(Invocation& invocation) const
{
// This is the type for the input domain
using InputDomainType = typename Invocation::InputDomainType;
@ -226,7 +226,7 @@ public:
// a DynamicArrayHandle that gets cast to one). The size of the domain
// (number of threads/worklet instances) is equal to the size of the
// array.
vtkm::Id fullSize = inputDomain.GetNumberOfValues();
vtkm::Id fullSize = internal::scheduling_range(inputDomain);
vtkm::Id blockSize = fullSize / NumberOfBlocks;
if (fullSize % NumberOfBlocks != 0)
blockSize += 1;
@ -259,7 +259,7 @@ public:
// Loop over parameters again to sync results for this block into control array
using ParameterInterfaceType2 = typename ChangedType::ParameterInterface;
const ParameterInterfaceType2& parameters2 = changedParams.Parameters;
ParameterInterfaceType2& parameters2 = changedParams.Parameters;
parameters2.StaticTransformCont(TransferFunctorType());
}
}
@ -269,14 +269,14 @@ private:
typename InputRangeType,
typename OutputRangeType,
typename DeviceAdapter>
VTKM_CONT void InvokeTransportParameters(const Invocation& invocation,
VTKM_CONT void InvokeTransportParameters(Invocation& invocation,
const InputRangeType& inputRange,
const InputRangeType& globalIndexOffset,
const OutputRangeType& outputRange,
DeviceAdapter device) const
{
using ParameterInterfaceType = typename Invocation::ParameterInterface;
const ParameterInterfaceType& parameters = invocation.Parameters;
ParameterInterfaceType& parameters = invocation.Parameters;
using TransportFunctorType = vtkm::worklet::internal::detail::DispatcherBaseTransportFunctor<
typename Invocation::ControlInterface,

@ -57,6 +57,34 @@ namespace worklet
{
namespace internal
{
template <typename Domain>
inline auto scheduling_range(const Domain& inputDomain) -> decltype(inputDomain.GetNumberOfValues())
{
return inputDomain.GetNumberOfValues();
}
template <typename Domain>
inline auto scheduling_range(const Domain* const inputDomain)
-> decltype(inputDomain->GetNumberOfValues())
{
return inputDomain->GetNumberOfValues();
}
template <typename Domain, typename SchedulingRangeType>
inline auto scheduling_range(const Domain& inputDomain, SchedulingRangeType type)
-> decltype(inputDomain.GetSchedulingRange(type))
{
return inputDomain.GetSchedulingRange(type);
}
template <typename Domain, typename SchedulingRangeType>
inline auto scheduling_range(const Domain* const inputDomain, SchedulingRangeType type)
-> decltype(inputDomain->GetSchedulingRange(type))
{
return inputDomain->GetSchedulingRange(type);
}
namespace detail
{
@ -76,6 +104,47 @@ inline void PrintFailureMessage(int index)
throw vtkm::cont::ErrorBadType(message.str());
}
inline void PrintNullPtrMessage(int index, int mode)
{
std::stringstream message;
if (mode == 0)
{
message << "Encountered nullptr for parameter " << index;
}
else
{
message << "Encountered nullptr for " << index << " from last parameter ";
}
message << " when calling Invoke on a dispatcher.";
throw vtkm::cont::ErrorBadValue(message.str());
}
template <typename T>
inline void not_nullptr(T* ptr, int index, int mode = 0)
{
if (!ptr)
{
PrintNullPtrMessage(index, mode);
}
}
template <typename T>
inline void not_nullptr(T&&, int, int mode = 0)
{
(void)mode;
}
template <typename T>
inline T& as_ref(T* ptr)
{
return *ptr;
}
template <typename T>
inline T&& as_ref(T&& t)
{
return std::forward<T>(t);
}
template <typename T, bool noError>
struct ReportTypeOnError;
template <typename T>
@ -90,10 +159,16 @@ struct ReportValueOnError<Value, true> : std::true_type
{
};
template <typename T>
struct remove_pointer_and_decay : std::remove_pointer<typename std::decay<T>::type>
{
};
// Is designed as a brigand fold operation.
template <typename T, typename State>
template <typename Type, typename State>
struct DetermineIfHasDynamicParameter
{
using T = typename std::remove_pointer<Type>::type;
using DynamicTag = typename vtkm::cont::internal::DynamicTransformTraits<T>::DynamicTag;
using isDynamic =
typename std::is_same<DynamicTag, vtkm::cont::internal::DynamicTransformTagCastAndCall>::type;
@ -106,7 +181,7 @@ struct DetermineIfHasDynamicParameter
template <typename WorkletType>
struct DetermineHasCorrectParameters
{
template <typename T, typename State, typename SigTypes>
template <typename Type, typename State, typename SigTypes>
struct Functor
{
//T is the type of the Param at the current index
@ -114,6 +189,7 @@ struct DetermineHasCorrectParameters
using ControlSignatureTag = typename brigand::at_c<SigTypes, State::value>;
using TypeCheckTag = typename ControlSignatureTag::TypeCheckTag;
using T = typename std::remove_pointer<Type>::type;
static constexpr bool isCorrect = vtkm::cont::arg::TypeCheck<TypeCheckTag, T>::value;
// If you get an error on the line below, that means that your code has called the
@ -224,27 +300,46 @@ struct DispatcherBaseTransportFunctor
{
}
template <typename ControlParameter, vtkm::IdComponent Index>
struct ReturnType
{
using TransportTag =
typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
using TransportType =
typename vtkm::cont::arg::Transport<TransportTag, ControlParameter, Device>;
using T = typename remove_pointer_and_decay<ControlParameter>::type;
using TransportType = typename vtkm::cont::arg::Transport<TransportTag, T, Device>;
using type = typename TransportType::ExecObjectType;
};
// template<typename ControlParameter, vtkm::IdComponent Index>
// VTKM_CONT typename ReturnType<ControlParameter, Index>::type operator()(
// ControlParameter const& invokeData,
// vtkm::internal::IndexTag<Index>) const
// {
// using TransportTag =
// typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
// using T = typename remove_pointer_and_decay<ControlParameter>::type;
// vtkm::cont::arg::Transport<TransportTag, T, Device> transport;
// return transport(invokeData, as_ref(this->InputDomain), this->InputRange, this->OutputRange);
// }
template <typename ControlParameter, vtkm::IdComponent Index>
VTKM_CONT typename ReturnType<ControlParameter, Index>::type operator()(
const ControlParameter& invokeData,
ControlParameter&& invokeData,
vtkm::internal::IndexTag<Index>) const
{
using TransportTag =
typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
vtkm::cont::arg::Transport<TransportTag, ControlParameter, Device> transport;
return transport(invokeData, this->InputDomain, this->InputRange, this->OutputRange);
using T = typename remove_pointer_and_decay<ControlParameter>::type;
vtkm::cont::arg::Transport<TransportTag, T, Device> transport;
not_nullptr(invokeData, Index);
return transport(
as_ref(invokeData), as_ref(this->InputDomain), this->InputRange, this->OutputRange);
}
private:
void operator=(const DispatcherBaseTransportFunctor&) = delete;
};
@ -306,7 +401,8 @@ inline void convert_arg(vtkm::cont::internal::DynamicTransformTagCastAndCall,
using tag_check = typename brigand::at_c<ContParams, 0>::TypeCheckTag;
using popped_sig = brigand::pop_front<ContParams>;
vtkm::cont::CastAndCall(t,
not_nullptr(t, LeftToProcess, 1);
vtkm::cont::CastAndCall(as_ref(t),
convert_arg_wrapper<LeftToProcess, tag_check>(),
trampoline,
popped_sig(),
@ -319,8 +415,8 @@ struct for_each_dynamic_arg
template <typename Trampoline, typename ContParams, typename T, typename... Args>
void operator()(const Trampoline& trampoline, ContParams&& sig, T&& t, Args&&... args) const
{
//Determine that state of T
using Type = typename std::decay<T>::type;
//Determine that state of T when it is either a `cons&` or a `* const&`
using Type = typename std::remove_pointer<typename std::decay<T>::type>::type;
using tag = typename vtkm::cont::internal::DynamicTransformTraits<Type>::DynamicTag;
//convert the first item to a known type
convert_arg<LeftToProcess>(
@ -456,7 +552,8 @@ private:
// argument) and the ControlSignature tags (in the ControlInterface type).
using ContParamsInfo =
vtkm::internal::detail::FunctionSigInfo<typename WorkletType::ControlSignature>;
detail::deduce(*this, typename ContParamsInfo::Parameters(), std::forward<Args>(args)...);
typename ContParamsInfo::Parameters parameters;
detail::deduce(*this, parameters, std::forward<Args>(args)...);
}
template <typename... Args>
@ -518,7 +615,7 @@ protected:
}
template <typename Invocation, typename DeviceAdapter>
VTKM_CONT void BasicInvoke(const Invocation& invocation,
VTKM_CONT void BasicInvoke(Invocation& invocation,
vtkm::Id numInstances,
DeviceAdapter device) const
{
@ -527,7 +624,7 @@ protected:
}
template <typename Invocation, typename DeviceAdapter>
VTKM_CONT void BasicInvoke(const Invocation& invocation,
VTKM_CONT void BasicInvoke(Invocation& invocation,
vtkm::Id2 dimensions,
DeviceAdapter device) const
{
@ -535,7 +632,7 @@ protected:
}
template <typename Invocation, typename DeviceAdapter>
VTKM_CONT void BasicInvoke(const Invocation& invocation,
VTKM_CONT void BasicInvoke(Invocation& invocation,
vtkm::Id3 dimensions,
DeviceAdapter device) const
{
@ -555,7 +652,7 @@ private:
typename InputRangeType,
typename OutputRangeType,
typename DeviceAdapter>
VTKM_CONT void InvokeTransportParameters(const Invocation& invocation,
VTKM_CONT void InvokeTransportParameters(Invocation& invocation,
const InputRangeType& inputRange,
OutputRangeType&& outputRange,
DeviceAdapter device) const
@ -570,7 +667,7 @@ private:
// static transform of the FunctionInterface to call the transport on each
// argument and return the corresponding execution environment object.
using ParameterInterfaceType = typename Invocation::ParameterInterface;
const ParameterInterfaceType& parameters = invocation.Parameters;
ParameterInterfaceType& parameters = invocation.Parameters;
using TransportFunctorType =
detail::DispatcherBaseTransportFunctor<typename Invocation::ControlInterface,

@ -33,16 +33,33 @@ using Device = vtkm::cont::DeviceAdapterTagSerial;
static constexpr vtkm::Id ARRAY_SIZE = 10;
struct TestExecObject
struct TestExecObjectIn
{
VTKM_EXEC_CONT
TestExecObject()
TestExecObjectIn()
: Array(nullptr)
{
}
VTKM_EXEC_CONT
TestExecObject(vtkm::Id* array)
TestExecObjectIn(const vtkm::Id* array)
: Array(array)
{
}
const vtkm::Id* Array;
};
struct TestExecObjectOut
{
VTKM_EXEC_CONT
TestExecObjectOut()
: Array(nullptr)
{
}
VTKM_EXEC_CONT
TestExecObjectOut(vtkm::Id* array)
: Array(array)
{
}
@ -85,7 +102,10 @@ struct TestExecObjectTypeBad
struct TestTypeCheckTag
{
};
struct TestTransportTag
struct TestTransportTagIn
{
};
struct TestTransportTagOut
{
};
struct TestFetchTagInput
@ -105,25 +125,43 @@ namespace arg
{
template <>
struct TypeCheck<TestTypeCheckTag, vtkm::Id*>
struct TypeCheck<TestTypeCheckTag, std::vector<vtkm::Id>>
{
static constexpr bool value = true;
};
template <>
struct Transport<TestTransportTag, vtkm::Id*, Device>
struct Transport<TestTransportTagIn, std::vector<vtkm::Id>, Device>
{
using ExecObjectType = TestExecObject;
using ExecObjectType = TestExecObjectIn;
VTKM_CONT
ExecObjectType operator()(vtkm::Id* contData,
vtkm::Id*,
ExecObjectType operator()(const std::vector<vtkm::Id>& contData,
const std::vector<vtkm::Id>&,
vtkm::Id inputRange,
vtkm::Id outputRange) const
{
VTKM_TEST_ASSERT(inputRange == ARRAY_SIZE, "Got unexpected size in test transport.");
VTKM_TEST_ASSERT(outputRange == ARRAY_SIZE, "Got unexpected size in test transport.");
return ExecObjectType(contData);
return ExecObjectType(contData.data());
}
};
template <>
struct Transport<TestTransportTagOut, std::vector<vtkm::Id>, Device>
{
using ExecObjectType = TestExecObjectOut;
VTKM_CONT
ExecObjectType operator()(const std::vector<vtkm::Id>& contData,
const std::vector<vtkm::Id>&,
vtkm::Id inputRange,
vtkm::Id outputRange) const
{
VTKM_TEST_ASSERT(inputRange == ARRAY_SIZE, "Got unexpected size in test transport.");
VTKM_TEST_ASSERT(outputRange == ARRAY_SIZE, "Got unexpected size in test transport.");
auto ptr = const_cast<vtkm::Id*>(contData.data());
return ExecObjectType(ptr);
}
};
}
@ -162,19 +200,19 @@ template <>
struct Fetch<TestFetchTagInput,
vtkm::exec::arg::AspectTagDefault,
vtkm::exec::arg::ThreadIndicesBasic,
TestExecObject>
TestExecObjectIn>
{
using ValueType = vtkm::Id;
VTKM_EXEC
ValueType Load(const vtkm::exec::arg::ThreadIndicesBasic indices,
const TestExecObject& execObject) const
const TestExecObjectIn& execObject) const
{
return execObject.Array[indices.GetInputIndex()];
}
VTKM_EXEC
void Store(const vtkm::exec::arg::ThreadIndicesBasic, const TestExecObject&, ValueType) const
void Store(const vtkm::exec::arg::ThreadIndicesBasic, const TestExecObjectIn&, ValueType) const
{
// No-op
}
@ -184,12 +222,12 @@ template <>
struct Fetch<TestFetchTagOutput,
vtkm::exec::arg::AspectTagDefault,
vtkm::exec::arg::ThreadIndicesBasic,
TestExecObject>
TestExecObjectOut>
{
using ValueType = vtkm::Id;
VTKM_EXEC
ValueType Load(const vtkm::exec::arg::ThreadIndicesBasic&, const TestExecObject&) const
ValueType Load(const vtkm::exec::arg::ThreadIndicesBasic&, const TestExecObjectOut&) const
{
// No-op
return ValueType();
@ -197,7 +235,7 @@ struct Fetch<TestFetchTagOutput,
VTKM_EXEC
void Store(const vtkm::exec::arg::ThreadIndicesBasic& indices,
const TestExecObject& execObject,
const TestExecObjectOut& execObject,
ValueType value) const
{
execObject.Array[indices.GetOutputIndex()] = value;
@ -218,13 +256,13 @@ public:
struct TestIn : vtkm::cont::arg::ControlSignatureTagBase
{
using TypeCheckTag = TestTypeCheckTag;
using TransportTag = TestTransportTag;
using TransportTag = TestTransportTagIn;
using FetchTag = TestFetchTagInput;
};
struct TestOut : vtkm::cont::arg::ControlSignatureTagBase
{
using TypeCheckTag = TestTypeCheckTag;
using TransportTag = TestTransportTag;
using TransportTag = TestTransportTagOut;
using FetchTag = TestFetchTagOutput;
};
};
@ -294,25 +332,27 @@ void TestBasicInvoke()
{
std::cout << "Test basic invoke" << std::endl;
std::cout << " Set up data." << std::endl;
vtkm::Id inputArray[ARRAY_SIZE];
vtkm::Id outputArray[ARRAY_SIZE];
std::vector<vtkm::Id> inputArray(ARRAY_SIZE);
std::vector<vtkm::Id> outputArray(ARRAY_SIZE);
TestExecObjectType execObject;
execObject.Value = EXPECTED_EXEC_OBJECT_VALUE;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
std::size_t i = 0;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++, i++)
{
inputArray[index] = TestValue(index, vtkm::Id());
outputArray[index] = static_cast<vtkm::Id>(0xDEADDEAD);
inputArray[i] = TestValue(index, vtkm::Id());
outputArray[i] = static_cast<vtkm::Id>(0xDEADDEAD);
}
std::cout << " Create and run dispatcher." << std::endl;
TestDispatcher<TestWorklet> dispatcher;
dispatcher.Invoke(inputArray, execObject, outputArray);
dispatcher.Invoke(inputArray, execObject, &outputArray);
std::cout << " Check output of invoke." << std::endl;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
i = 0;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++, i++)
{
VTKM_TEST_ASSERT(outputArray[index] == TestValue(index, vtkm::Id()) + 1000,
VTKM_TEST_ASSERT(outputArray[i] == TestValue(index, vtkm::Id()) + 1000,
"Got bad value from testing.");
}
}
@ -321,22 +361,23 @@ void TestInvokeWithError()
{
std::cout << "Test invoke with error raised" << std::endl;
std::cout << " Set up data." << std::endl;
vtkm::Id inputArray[ARRAY_SIZE];
vtkm::Id outputArray[ARRAY_SIZE];
std::vector<vtkm::Id> inputArray(ARRAY_SIZE);
std::vector<vtkm::Id> outputArray(ARRAY_SIZE);
TestExecObjectType execObject;
execObject.Value = EXPECTED_EXEC_OBJECT_VALUE;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
std::size_t i = 0;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++, ++i)
{
inputArray[index] = TestValue(index, vtkm::Id());
outputArray[index] = static_cast<vtkm::Id>(0xDEADDEAD);
inputArray[i] = TestValue(index, vtkm::Id());
outputArray[i] = static_cast<vtkm::Id>(0xDEADDEAD);
}
try
{
std::cout << " Create and run dispatcher that raises error." << std::endl;
TestDispatcher<TestErrorWorklet> dispatcher;
dispatcher.Invoke(inputArray, execObject, outputArray);
dispatcher.Invoke(&inputArray, execObject, outputArray);
VTKM_TEST_FAIL("Exception not thrown.");
}
catch (vtkm::cont::ErrorExecution& error)
@ -350,8 +391,8 @@ void TestInvokeWithBadDynamicType()
{
std::cout << "Test invoke with bad type" << std::endl;
vtkm::Id inputArray[ARRAY_SIZE];
vtkm::Id outputArray[ARRAY_SIZE];
std::vector<vtkm::Id> inputArray(ARRAY_SIZE);
std::vector<vtkm::Id> outputArray(ARRAY_SIZE);
TestExecObjectTypeBad execObject;
TestDispatcher<TestWorklet> dispatcher;

@ -87,11 +87,11 @@ struct TestWholeCellSetIn
numberOfElements,
shapeIds,
numberOfIndices,
connectionSum);
&connectionSum);
}
template <typename CellSetType>
VTKM_CONT static void RunPoints(const CellSetType& cellSet,
VTKM_CONT static void RunPoints(const CellSetType* cellSet,
vtkm::cont::ArrayHandle<vtkm::Id> numberOfElements,
vtkm::cont::ArrayHandle<vtkm::UInt8> shapeIds,
vtkm::cont::ArrayHandle<vtkm::IdComponent> numberOfIndices,
@ -100,10 +100,10 @@ struct TestWholeCellSetIn
using WorkletType =
WholeCellSetWorklet<vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint>;
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
dispatcher.Invoke(vtkm::cont::ArrayHandleIndex(cellSet.GetNumberOfPoints()),
dispatcher.Invoke(vtkm::cont::ArrayHandleIndex(cellSet->GetNumberOfPoints()),
cellSet,
numberOfElements,
shapeIds,
&shapeIds,
numberOfIndices,
connectionSum);
}
@ -169,7 +169,7 @@ VTKM_CONT void TryPointConnectivity(const CellSetType& cellSet,
vtkm::cont::ArrayHandle<vtkm::Id> connectionSum;
TestWholeCellSetIn::RunPoints(
cellSet, numberOfElements, shapeIds, numberOfIndices, connectionSum);
&cellSet, numberOfElements, shapeIds, numberOfIndices, connectionSum);
std::cout << " Number of elements: " << numberOfElements.GetPortalConstControl().Get(0)
<< std::endl;

@ -97,18 +97,22 @@ struct DoStaticTestWorklet
}
vtkm::cont::ArrayHandle<T> inputHandle = vtkm::cont::make_ArrayHandle(inputArray, ARRAY_SIZE);
vtkm::cont::ArrayHandle<T> outputHandle;
vtkm::cont::ArrayHandle<T> inoutHandle;
vtkm::cont::ArrayHandle<T> outputHandle, outputHandleAsPtr;
vtkm::cont::ArrayHandle<T> inoutHandle, inoutHandleAsPtr;
vtkm::cont::ArrayCopy(inputHandle, inoutHandle, VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::ArrayCopy(inputHandle, inoutHandleAsPtr, VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
std::cout << "Create and run dispatcher." << std::endl;
std::cout << "Create and run dispatchers." << std::endl;
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
dispatcher.Invoke(inputHandle, outputHandle, inoutHandle);
dispatcher.Invoke(&inputHandle, &outputHandleAsPtr, &inoutHandleAsPtr);
std::cout << "Check result." << std::endl;
std::cout << "Check results." << std::endl;
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
CheckPortal(outputHandleAsPtr.GetPortalConstControl());
CheckPortal(inoutHandleAsPtr.GetPortalConstControl());
std::cout << "Try to invoke with an input array of the wrong size." << std::endl;
inputHandle.Shrink(ARRAY_SIZE / 2);
@ -144,19 +148,29 @@ struct DoDynamicTestWorklet
vtkm::cont::ArrayHandle<T> outputHandle;
vtkm::cont::ArrayHandle<T> inoutHandle;
vtkm::cont::ArrayCopy(inputHandle, inoutHandle, VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
std::cout << "Create and run dispatcher with dynamic arrays." << std::endl;
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
dispatcher.Invoke(inputDynamic, outputDynamic, inoutDynamic);
{ //Verify we can pass by value
vtkm::cont::ArrayCopy(inputHandle, inoutHandle, VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
dispatcher.Invoke(inputDynamic, outputDynamic, inoutDynamic);
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
}
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
{ //Verify we can pass by pointer
vtkm::cont::ArrayCopy(inputHandle, inoutHandle, VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
dispatcher.Invoke(&inputDynamic, &outputDynamic, &inoutDynamic);
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
}
}
};

@ -92,12 +92,12 @@ static void TestMaxPointOrCell()
std::cout << "Testing MaxPointOfCell worklet" << std::endl;
vtkm::cont::testing::MakeTestDataSet testDataSet;
vtkm::cont::DataSet dataSet = testDataSet.Make3DExplicitDataSet0();
auto cellset = dataSet.GetCellSet(0).Cast<vtkm::cont::CellSetExplicit<>>();
vtkm::cont::ArrayHandle<vtkm::Float32> result;
vtkm::worklet::DispatcherMapTopology<::test_explicit::MaxPointOrCellValue> dispatcher;
dispatcher.Invoke(
dataSet.GetField("cellvar"), dataSet.GetField("pointvar"), dataSet.GetCellSet(0), result);
dispatcher.Invoke(dataSet.GetField("cellvar"), dataSet.GetField("pointvar"), &cellset, result);
std::cout << "Make sure we got the right answer." << std::endl;
VTKM_TEST_ASSERT(test_equal(result.GetPortalConstControl().Get(0), 100.1f),
@ -112,11 +112,12 @@ static void TestAvgPointToCell()
vtkm::cont::testing::MakeTestDataSet testDataSet;
vtkm::cont::DataSet dataSet = testDataSet.Make3DExplicitDataSet0();
auto cellset = dataSet.GetCellSet();
vtkm::cont::ArrayHandle<vtkm::Float32> result;
vtkm::worklet::DispatcherMapTopology<vtkm::worklet::CellAverage> dispatcher;
dispatcher.Invoke(dataSet.GetCellSet(), dataSet.GetField("pointvar"), result);
dispatcher.Invoke(&cellset, dataSet.GetField("pointvar"), &result);
std::cout << "Make sure we got the right answer." << std::endl;
VTKM_TEST_ASSERT(test_equal(result.GetPortalConstControl().Get(0), 20.1333f),
@ -146,11 +147,12 @@ static void TestAvgCellToPoint()
vtkm::cont::testing::MakeTestDataSet testDataSet;
vtkm::cont::DataSet dataSet = testDataSet.Make3DExplicitDataSet1();
auto field = dataSet.GetField("cellvar");
vtkm::cont::ArrayHandle<vtkm::Float32> result;
vtkm::worklet::DispatcherMapTopology<vtkm::worklet::PointAverage> dispatcher;
dispatcher.Invoke(dataSet.GetCellSet(), dataSet.GetField("cellvar"), result);
dispatcher.Invoke(dataSet.GetCellSet(), &field, result);
std::cout << "Make sure we got the right answer." << std::endl;
VTKM_TEST_ASSERT(test_equal(result.GetPortalConstControl().Get(0), 100.1f),

@ -145,13 +145,15 @@ static void TestAvgPointToCell()
vtkm::cont::ArrayHandle<vtkm::Float32> result;
auto cellset = dataSet.GetCellSet(0).ResetCellSetList(vtkm::cont::CellSetListTagStructured2D());
vtkm::worklet::DispatcherMapTopology<vtkm::worklet::CellAverage> dispatcher;
dispatcher.Invoke(
// We know that the cell set is a structured 2D grid and
// The worklet does not work with general types because
// of the way we get cell indices. We need to make that
// part more flexible.
dataSet.GetCellSet(0).ResetCellSetList(vtkm::cont::CellSetListTagStructured2D()),
&cellset,
dataSet.GetField("pointvar"),
result);