10 #ifndef vtk_m_worklet_internal_DispatcherBase_h
11 #define vtk_m_worklet_internal_DispatcherBase_h
34 #include <vtkmstd/integer_sequence.h>
35 #include <vtkmstd/is_trivial.h>
46 template <
typename Domain>
47 inline auto SchedulingRange(
const Domain& inputDomain) -> decltype(inputDomain.GetNumberOfValues())
49 return inputDomain.GetNumberOfValues();
52 template <
typename Domain>
53 inline auto SchedulingRange(
const Domain*
const inputDomain)
54 -> decltype(inputDomain->GetNumberOfValues())
56 return inputDomain->GetNumberOfValues();
59 template <
typename Domain,
typename SchedulingRangeType>
60 inline auto SchedulingRange(
const Domain& inputDomain, SchedulingRangeType type)
61 -> decltype(inputDomain.GetSchedulingRange(type))
63 return inputDomain.GetSchedulingRange(type);
66 template <
typename Domain,
typename SchedulingRangeType>
67 inline auto SchedulingRange(
const Domain*
const inputDomain, SchedulingRangeType type)
68 -> decltype(inputDomain->GetSchedulingRange(type))
70 return inputDomain->GetSchedulingRange(type);
84 inline void PrintFailureMessage(
int index)
86 std::stringstream message;
87 message <<
"Encountered bad type for parameter " << index
88 <<
" when calling Invoke on a dispatcher.";
92 inline void PrintNullPtrMessage(
int index,
int mode)
94 std::stringstream message;
97 message <<
"Encountered nullptr for parameter " << index;
101 message <<
"Encountered nullptr for " << index <<
" from last parameter ";
103 message <<
" when calling Invoke on a dispatcher.";
107 template <
typename T>
108 inline void not_nullptr(T* ptr,
int index,
int mode = 0)
112 PrintNullPtrMessage(index, mode);
115 template <
typename T>
116 inline void not_nullptr(T&&,
int,
int mode = 0)
121 template <
typename T>
122 inline T& as_ref(T* ptr)
126 template <
typename T>
127 inline T&& as_ref(T&& t)
129 return std::forward<T>(t);
133 template <
typename T,
bool noError>
134 struct ReportTypeOnError : std::integral_constant<bool, noError>
138 template <
int Value,
bool noError>
139 struct ReportValueOnError : std::integral_constant<bool, noError>
143 template <
typename Type>
144 struct IsDynamicTypeImpl
146 using T = vtkm::internal::remove_pointer_and_decay<Type>;
147 using DynamicTag =
typename vtkm::cont::internal::DynamicTransformTraits<T>::DynamicTag;
149 typename std::is_same<DynamicTag, vtkm::cont::internal::DynamicTransformTagCastAndCall>::type;
151 template <
typename T>
152 using IsDynamicType =
typename IsDynamicTypeImpl<T>::type;
154 template <
typename SigTagList,
typename ParamList,
typename IndexSequence>
155 struct ZipControlParamImpl;
157 struct ZipControlParamImpl<
vtkm::List<SigTags...>,
159 vtkmstd::integer_sequence<vtkm::IdComponent, Indices...>>
167 template <
typename SigTagList,
typename ParamList,
typename IndexSequence>
168 using ZipControlParam =
typename ZipControlParamImpl<SigTagList, ParamList, IndexSequence>::type;
170 template <
typename WorkletType>
171 struct ControlArgumentValidator
173 template <
typename SigTag,
typename Param, vtkm::IdComponent Index>
174 void operator()(
vtkm::List<SigTag, Param, std::integral_constant<vtkm::IdComponent, Index>>)
const
176 using T = std::remove_pointer_t<Param>;
177 using TypeCheckTag =
typename SigTag::TypeCheckTag;
182 "If you get an error here, that means that your code has invoked a worklet,"
183 " and one of the arguments of the Invoke is the wrong type. Each argument of the invoke"
184 " corresponds to a tag in the arguments of the ControlSignature of the worklet. If there"
185 " is a mismatch, then you get an error here (instead of where you called invoke). For"
186 " example, if the worklet has a control signature as ControlSignature(CellSetIn, ...) and"
187 " the first argument passed to the invoke is an ArrayHandle, you will get an error here"
188 " because you cannot use an ArrayHandle in place of a CellSetIn argument. (You need to use"
189 " a CellSet.) If the compiler supports it, the next few errors on the following lines of"
190 " code will give information about where the error actually occurred.");
200 static_assert(ReportTypeOnError<WorkletType, isCorrect>::value,
201 "The first template argument to ReportTypeOnError is the worklet being invoked");
202 static_assert(ReportValueOnError<Index, isCorrect>::value,
203 "The first template argument to ReportTypeOnError is the index of Invoke "
204 "parameter (starting at index 1)");
205 static_assert(ReportTypeOnError<T, isCorrect>::value,
206 "The first template argument to ReportTypeOnError is the type passed to Invoke");
207 static_assert(ReportTypeOnError<TypeCheckTag, isCorrect>::value,
208 "The first template argument to ReportTypeOnError is the type check tag used");
214 struct DispatcherBaseControlSignatureTagCheck
216 template <
typename ControlSignatureTag, vtkm::IdComponent Index>
222 using type = ControlSignatureTag;
228 struct DispatcherBaseExecutionSignatureTagCheck
230 template <
typename ExecutionSignatureTag, vtkm::IdComponent Index>
236 using type = ExecutionSignatureTag;
240 struct DispatcherBaseTryExecuteFunctor
242 template <
typename Device,
typename DispatcherBaseType,
typename Invocation,
typename RangeType>
244 const DispatcherBaseType*
self,
245 Invocation& invocation,
246 const RangeType& dimensions)
248 auto outputRange =
self->Scatter.GetOutputRange(dimensions);
249 self->InvokeTransportParameters(
250 invocation, dimensions, outputRange, self->Mask.GetThreadRange(outputRange), device);
257 template <
typename ControlInterface, vtkm::IdComponent Index>
258 struct DispatcherBaseTransportInvokeTypes
261 using ControlSignatureTag =
typename ControlInterface::template ParameterType<Index>::type;
262 using TransportTag =
typename ControlSignatureTag::TransportTag;
274 return range[0] * range[1] * range[2];
279 template <
typename ControlInterface,
typename InputDomainType,
typename Device>
280 struct DispatcherBaseTransportFunctor
282 const InputDomainType& InputDomain;
291 template <
typename InputRangeType,
typename OutputRangeType>
292 VTKM_CONT DispatcherBaseTransportFunctor(
const InputDomainType& inputDomain,
293 const InputRangeType& inputRange,
294 const OutputRangeType& outputRange,
296 : InputDomain(inputDomain)
297 , InputRange(FlatRange(inputRange))
298 , OutputRange(FlatRange(outputRange))
304 template <
typename ControlParameter, vtkm::IdComponent Index>
308 typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
309 using T = vtkm::internal::remove_pointer_and_decay<ControlParameter>;
311 using type =
typename std::decay<typename TransportType::ExecObjectType>::type;
319 VTKM_IS_TRIVIALLY_COPYABLE(type);
322 template <
typename ControlParameter, vtkm::IdComponent Index>
323 VTKM_CONT typename ReturnType<ControlParameter, Index>::type operator()(
324 ControlParameter&& invokeData,
325 vtkm::internal::IndexTag<Index>)
const
328 typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
329 using T = vtkm::internal::remove_pointer_and_decay<ControlParameter>;
332 not_nullptr(invokeData,
Index);
333 return transport(as_ref(invokeData),
334 as_ref(this->InputDomain),
343 void operator=(
const DispatcherBaseTransportFunctor&) =
delete;
348 template <
typename L>
349 struct ListRemoveFirstImpl;
350 template <
typename T,
typename... Ts>
351 struct ListRemoveFirstImpl<
vtkm::List<T, Ts...>>
355 template <
typename L>
356 using ListRemoveFirst =
typename ListRemoveFirstImpl<L>::type;
359 template <std::
size_t LeftToProcess>
360 struct for_each_dynamic_arg;
362 template <std::
size_t LeftToProcess,
typename TypeCheckTag>
363 struct convert_arg_wrapper
365 template <
typename T,
typename... Args>
366 void operator()(T&& t, Args&&... args)
const
368 using Type =
typename std::decay<T>::type;
370 std::integral_constant<bool, vtkm::cont::arg::TypeCheck<TypeCheckTag, Type>::value>;
371 this->WillContinue(valid(), std::forward<T>(t), std::forward<Args>(args)...);
373 template <
typename T,
typename... Args>
374 void WillContinue(std::true_type, T&& t, Args&&... args)
const
376 for_each_dynamic_arg<LeftToProcess - 1>()(std::forward<Args>(args)..., std::forward<T>(t));
378 template <
typename... Args>
379 void WillContinue(std::false_type, Args&&...)
const
381 vtkm::worklet::internal::detail::PrintFailureMessage(LeftToProcess);
385 template <std::size_t LeftToProcess,
390 inline void convert_arg(vtkm::cont::internal::DynamicTransformTagStatic,
393 const Trampoline& trampoline,
396 using popped_sig = ListRemoveFirst<ContParams>;
397 for_each_dynamic_arg<LeftToProcess - 1>()(
398 trampoline, popped_sig(), std::forward<Args>(args)..., std::forward<T>(t));
401 template <std::size_t LeftToProcess,
406 inline void convert_arg(vtkm::cont::internal::DynamicTransformTagCastAndCall,
409 const Trampoline& trampoline,
413 using popped_sig = ListRemoveFirst<ContParams>;
415 not_nullptr(t, LeftToProcess, 1);
417 convert_arg_wrapper<LeftToProcess, tag_check>(),
420 std::forward<Args>(args)...);
423 template <std::
size_t LeftToProcess>
424 struct for_each_dynamic_arg
426 template <
typename Trampoline,
typename ContParams,
typename T,
typename... Args>
427 void operator()(
const Trampoline& trampoline, ContParams&& sig, T&& t, Args&&... args)
const
430 using Type = vtkm::internal::remove_pointer_and_decay<T>;
431 using tag =
typename vtkm::cont::internal::DynamicTransformTraits<Type>::DynamicTag;
433 convert_arg<LeftToProcess>(
434 tag(), std::forward<T>(t), sig, trampoline, std::forward<Args>(args)...);
439 struct for_each_dynamic_arg<0>
441 template <
typename Trampoline,
typename ContParams,
typename... Args>
442 void operator()(
const Trampoline& trampoline, ContParams&&, Args&&... args)
const
444 trampoline.StartInvokeDynamic(std::false_type(), std::forward<Args>(args)...);
448 template <
typename Trampoline,
typename ContParams,
typename... Args>
449 inline void deduce(Trampoline&& trampoline, ContParams&& sig, Args&&... args)
451 for_each_dynamic_arg<
sizeof...(Args)>()(std::forward<Trampoline>(trampoline), sig, args...);
458 template <vtkm::IdComponent MaxIndexAllowed>
459 struct PlaceholderValidator
461 PlaceholderValidator() {}
465 void operator()(vtkm::internal::meta::Type<vtkm::placeholders::Arg<N>>)
const
467 static_assert(N <= MaxIndexAllowed,
468 "An argument in the execution signature"
469 " (usually _2, _3, _4, etc.) refers to a control signature argument that"
470 " does not exist. For example, you will get this error if you have _3 (or"
471 " _4 or _5 or so on) as one of the execution signature arguments, but you"
472 " have fewer than 3 (or 4 or 5 or so on) arguments in the control signature.");
475 template <
typename DerivedType>
476 void operator()(vtkm::internal::meta::Type<DerivedType>)
const
484 template <
typename DerivedClass,
typename WorkletType,
typename BaseWorkletType>
488 using MyType = DispatcherBase<DerivedClass, WorkletType, BaseWorkletType>;
490 friend struct detail::for_each_dynamic_arg<0>;
493 using ControlInterface =
494 vtkm::internal::FunctionInterface<typename WorkletType::ControlSignature>;
498 using ExecutionSignature =
499 typename vtkm::placeholders::GetExecSig<WorkletType>::ExecutionSignature;
500 using ExecutionInterface = vtkm::internal::FunctionInterface<ExecutionSignature>;
507 using ControlSignatureCheck =
typename ControlInterface::template StaticTransformType<
508 detail::DispatcherBaseControlSignatureTagCheck>::type;
509 using ExecutionSignatureCheck =
typename ExecutionInterface::template StaticTransformType<
510 detail::DispatcherBaseExecutionSignatureTagCheck>::type;
512 template <
typename... Args>
513 VTKM_CONT void StartInvoke(Args&&... args)
const
515 using ParameterInterface =
516 vtkm::internal::FunctionInterface<void(vtkm::internal::remove_cvref<Args>...)>;
519 "Dispatcher Invoke called with wrong number of arguments.");
522 std::is_base_of<BaseWorkletType, WorkletType>::value,
523 "The worklet being scheduled by this dispatcher doesn't match the type of the dispatcher");
527 using ComponentSig =
typename ExecutionInterface::ComponentSig;
537 using ParamTypes =
typename ParameterInterface::ParameterSig;
540 this->StartInvokeDynamic(HasDynamicTypes(), std::forward<Args>(args)...);
543 template <
typename... Args>
544 VTKM_CONT void StartInvokeDynamic(std::true_type, Args&&... args)
const
550 using ContParamsInfo =
551 vtkm::internal::detail::FunctionSigInfo<typename WorkletType::ControlSignature>;
552 typename ContParamsInfo::Parameters parameters;
553 detail::deduce(*
this, parameters, std::forward<Args>(args)...);
556 template <
typename... Args>
557 VTKM_CONT void StartInvokeDynamic(std::false_type, Args&&... args)
const
559 using ParameterInterface =
560 vtkm::internal::FunctionInterface<void(vtkm::internal::remove_cvref<Args>...)>;
565 using ParamTypes =
typename ParameterInterface::ParameterSig;
566 using ContSigTypes =
typename vtkm::internal::detail::FunctionSigInfo<
567 typename WorkletType::ControlSignature>::Parameters;
568 using ParamZip = detail::ZipControlParam<
571 vtkmstd::make_integer_sequence<vtkm::IdComponent, vtkm::ListSize<ParamTypes>::value>>;
577 vtkm::internal::make_FunctionInterface<void, vtkm::internal::remove_cvref<Args>...>(args...);
578 auto ivc = vtkm::internal::Invocation<ParameterInterface,
581 WorkletType::InputDomain::INDEX,
582 vtkm::internal::NullType,
583 vtkm::internal::NullType>(
584 fi, vtkm::internal::NullType{}, vtkm::internal::NullType{});
585 static_cast<const DerivedClass*
>(
this)->DoInvoke(ivc);
600 using ScatterType =
typename WorkletType::ScatterType;
601 using MaskType =
typename WorkletType::MaskType;
603 template <
typename... Args>
604 VTKM_CONT void Invoke(Args&&... args)
const
607 "Invoking Worklet: '%s'",
608 vtkm::cont::TypeToString<DerivedClass>().c_str());
609 this->StartInvoke(std::forward<Args>(args)...);
618 DispatcherBase(
const WorkletType& worklet = WorkletType(),
619 const ScatterType& scatter = ScatterType(),
620 const MaskType& mask = MaskType())
624 , Device(
vtkm::cont::DeviceAdapterTagAny())
633 DispatcherBase(
const ScatterType& scatter,
const MaskType& mask = MaskType())
634 : Worklet(WorkletType())
637 , Device(
vtkm::cont::DeviceAdapterTagAny())
646 DispatcherBase(
const WorkletType& worklet,
647 const MaskType& mask,
648 const ScatterType& scatter = ScatterType())
652 , Device(
vtkm::cont::DeviceAdapterTagAny())
661 DispatcherBase(
const MaskType& mask,
const ScatterType& scatter = ScatterType())
662 : Worklet(WorkletType())
665 , Device(
vtkm::cont::DeviceAdapterTagAny())
669 friend struct internal::detail::DispatcherBaseTryExecuteFunctor;
671 template <
typename Invocation>
676 internal::detail::DispatcherBaseTryExecuteFunctor(),
686 template <
typename Invocation>
689 this->BasicInvoke(invocation,
vtkm::Id3(dimensions[0], dimensions[1], 1));
692 template <
typename Invocation>
697 internal::detail::DispatcherBaseTryExecuteFunctor(),
713 DispatcherBase(
const MyType&) =
delete;
714 void operator=(
const MyType&) =
delete;
718 template <
typename Invocation,
719 typename InputRangeType,
720 typename OutputRangeType,
721 typename ThreadRangeType,
722 typename DeviceAdapter>
723 VTKM_CONT void InvokeTransportParameters(Invocation& invocation,
724 const InputRangeType& inputRange,
725 OutputRangeType&& outputRange,
726 ThreadRangeType&& threadRange,
727 DeviceAdapter device)
const
742 using ParameterInterfaceType =
typename Invocation::ParameterInterface;
743 ParameterInterfaceType& parameters = invocation.Parameters;
745 using TransportFunctorType =
746 detail::DispatcherBaseTransportFunctor<
typename Invocation::ControlInterface,
747 typename Invocation::InputDomainType,
749 using ExecObjectParameters =
750 typename ParameterInterfaceType::template StaticTransformType<TransportFunctorType>::type;
752 ExecObjectParameters execObjectParameters = parameters.StaticTransformCont(
753 TransportFunctorType(invocation.GetInputDomain(), inputRange, outputRange, token));
756 typename ScatterType::OutputToInputMapType outputToInputMap =
757 this->Scatter.GetOutputToInputMap(inputRange);
758 typename ScatterType::VisitArrayType visitArray = this->Scatter.GetVisitArray(inputRange);
761 typename MaskType::ThreadToOutputMapType threadToOutputMap =
762 this->Mask.GetThreadToOutputMap(outputRange);
766 vtkm::internal::Invocation<ExecObjectParameters,
767 typename Invocation::ControlInterface,
768 typename Invocation::ExecutionInterface,
769 Invocation::InputDomainIndex,
770 decltype(outputToInputMap.PrepareForInput(device, token)),
771 decltype(visitArray.PrepareForInput(device, token)),
772 decltype(threadToOutputMap.PrepareForInput(device, token)),
774 changedInvocation(execObjectParameters,
775 outputToInputMap.PrepareForInput(device, token),
776 visitArray.PrepareForInput(device, token),
777 threadToOutputMap.PrepareForInput(device, token));
779 this->InvokeSchedule(changedInvocation, threadRange, device);
782 template <
typename Invocation,
typename RangeType,
typename DeviceAdapter>
783 VTKM_CONT void InvokeSchedule(
const Invocation& invocation, RangeType range, DeviceAdapter)
const
796 TaskTypes::MakeTask(this->Worklet, invocation, range,
typename WorkletType::Hints{});
797 Algorithm::ScheduleTask(task, range);
804 #endif //vtk_m_worklet_internal_DispatcherBase_h