1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 //  Copyright 2014 UT-Battelle, LLC.
11 //  Copyright 2014 Los Alamos National Security.
12 //
13 //  Under the terms of Contract DE-NA0003525 with NTESS,
14 //  the U.S. Government retains certain rights in this software.
15 //
16 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 //  Laboratory (LANL), the U.S. Government retains certain rights in
18 //  this software.
19 //============================================================================
20 #ifndef vtk_m_internal_Invocation_h
21 #define vtk_m_internal_Invocation_h
22 
23 #include <vtkm/Types.h>
24 
25 namespace vtkm
26 {
27 namespace internal
28 {
29 
30 /// \brief Container for types when dispatching worklets.
31 ///
32 /// When a dispatcher and associated class invoke a worklet, they need to keep
33 /// track of the types of all parameters and the associated features of the
34 /// worklet. \c Invocation is a class that manages all these types.
35 ///
36 template <typename _ParameterInterface,
37           typename _ControlInterface,
38           typename _ExecutionInterface,
39           vtkm::IdComponent _InputDomainIndex,
40           typename _OutputToInputMapType = vtkm::internal::NullType,
41           typename _VisitArrayType = vtkm::internal::NullType>
42 struct Invocation
43 {
44   /// \brief The types of the parameters
45   ///
46   /// \c ParameterInterface is (expected to be) a \c FunctionInterface class
47   /// that lists the types of the parameters for the invocation.
48   ///
49   using ParameterInterface = _ParameterInterface;
50 
51   /// \brief The tags of the \c ControlSignature.
52   ///
53   /// \c ControlInterface is (expected to be) a \c FunctionInterface class that
54   /// represents the \c ControlSignature of a worklet (although dispatchers
55   /// might modify the control signature to provide auxiliary information).
56   ///
57   using ControlInterface = _ControlInterface;
58 
59   /// \brief The tags of the \c ExecutionSignature.
60   ///
61   /// \c ExecutionInterface is (expected to be) a \c FunctionInterface class that
62   /// represents the \c ExecutionSignature of a worklet (although dispatchers
63   /// might modify the execution signature to provide auxiliary information).
64   ///
65   using ExecutionInterface = _ExecutionInterface;
66 
67   /// \brief The index of the input domain.
68   ///
69   /// When a worklet is invoked, the pool of working threads is based of some
70   /// constituent element of the input (such as the points or cells). This
71   /// index points to the parameter that defines this input domain.
72   ///
73   static constexpr vtkm::IdComponent InputDomainIndex = _InputDomainIndex;
74 
75   /// \brief An array representing the output to input map.
76   ///
77   /// When a worklet is invoked, there is an optional scatter operation that
78   /// allows you to vary the number of outputs each input affects. This is
79   /// represented with a map where each output points to an input that creates
80   /// it.
81   ///
82   using OutputToInputMapType = _OutputToInputMapType;
83 
84   /// \brief An array containing visit indices.
85   ///
86   /// When a worklet is invoked, there is an optinonal scatter operation that
87   /// allows you to vary the number of outputs each input affects. Thus,
88   /// multiple outputs may point to the same input. The visit index uniquely
89   /// identifies which instance each is.
90   ///
91   using VisitArrayType = _VisitArrayType;
92 
93   /// \brief Default Invocation constructors that holds the given parameters
94   /// by reference.
95   VTKM_CONT
96   Invocation(const ParameterInterface& parameters,
97              OutputToInputMapType outputToInputMap = OutputToInputMapType(),
98              VisitArrayType visitArray = VisitArrayType())
ParametersInvocation99     : Parameters(parameters)
100     , OutputToInputMap(outputToInputMap)
101     , VisitArray(visitArray)
102   {
103   }
104 
105   /// Defines a new \c Invocation type that is the same as this type except
106   /// with the \c Parameters replaced.
107   ///
108   template <typename NewParameterInterface>
109   struct ChangeParametersType
110   {
111     using type = Invocation<NewParameterInterface,
112                             ControlInterface,
113                             ExecutionInterface,
114                             InputDomainIndex,
115                             OutputToInputMapType,
116                             VisitArrayType>;
117   };
118 
119   /// Returns a new \c Invocation that is the same as this one except that the
120   /// \c Parameters are replaced with those provided.
121   ///
122   template <typename NewParameterInterface>
ChangeParametersInvocation123   VTKM_CONT typename ChangeParametersType<NewParameterInterface>::type ChangeParameters(
124     const NewParameterInterface& newParameters) const
125   {
126     return typename ChangeParametersType<NewParameterInterface>::type(
127       newParameters, this->OutputToInputMap, this->VisitArray);
128   }
129 
130   /// Defines a new \c Invocation type that is the same as this type except
131   /// with the \c ControlInterface replaced.
132   ///
133   template <typename NewControlInterface>
134   struct ChangeControlInterfaceType
135   {
136     using type =
137       Invocation<ParameterInterface, NewControlInterface, ExecutionInterface, InputDomainIndex>;
138   };
139 
140   /// Returns a new \c Invocation that is the same as this one except that the
141   /// \c ControlInterface type is changed to the type given.
142   ///
143   template <typename NewControlInterface>
ChangeControlInterfaceInvocation144   typename ChangeControlInterfaceType<NewControlInterface>::type ChangeControlInterface(
145     NewControlInterface) const
146   {
147     return typename ChangeControlInterfaceType<NewControlInterface>::type(
148       this->Parameters, this->OutputToInputMap, this->VisitArray);
149   }
150 
151   /// Defines a new \c Invocation type that is the same as this type except
152   /// with the \c ExecutionInterface replaced.
153   ///
154   template <typename NewExecutionInterface>
155   struct ChangeExecutionInterfaceType
156   {
157     using type =
158       Invocation<ParameterInterface, NewExecutionInterface, ExecutionInterface, InputDomainIndex>;
159   };
160 
161   /// Returns a new \c Invocation that is the same as this one except that the
162   /// \c ExecutionInterface type is changed to the type given.
163   ///
164   template <typename NewExecutionInterface>
ChangeExecutionInterfaceInvocation165   typename ChangeExecutionInterfaceType<NewExecutionInterface>::type ChangeExecutionInterface(
166     NewExecutionInterface) const
167   {
168     return typename ChangeExecutionInterfaceType<NewExecutionInterface>::type(
169       this->Parameters, this->OutputToInputMap, this->VisitArray);
170   }
171 
172   /// Defines a new \c Invocation type that is the same as this type except
173   /// with the \c InputDomainIndex replaced.
174   ///
175   template <vtkm::IdComponent NewInputDomainIndex>
176   struct ChangeInputDomainIndexType
177   {
178     using type =
179       Invocation<ParameterInterface, ControlInterface, ExecutionInterface, NewInputDomainIndex>;
180   };
181 
182   /// Returns a new \c Invocation that is the same as this one except that the
183   /// \c InputDomainIndex is changed to the static number given.
184   ///
185   template <vtkm::IdComponent NewInputDomainIndex>
186   VTKM_EXEC_CONT typename ChangeInputDomainIndexType<NewInputDomainIndex>::type
ChangeInputDomainIndexInvocation187   ChangeInputDomainIndex() const
188   {
189     return typename ChangeInputDomainIndexType<NewInputDomainIndex>::type(
190       this->Parameters, this->OutputToInputMap, this->VisitArray);
191   }
192 
193   /// Defines a new \c Invocation type that is the same as this type except
194   /// with the \c OutputToInputMapType replaced.
195   ///
196   template <typename NewOutputToInputMapType>
197   struct ChangeOutputToInputMapType
198   {
199     using type = Invocation<ParameterInterface,
200                             ControlInterface,
201                             ExecutionInterface,
202                             InputDomainIndex,
203                             NewOutputToInputMapType,
204                             VisitArrayType>;
205   };
206 
207   /// Returns a new \c Invocation that is the same as this one except that the
208   /// \c OutputToInputMap is replaced with that provided.
209   ///
210   template <typename NewOutputToInputMapType>
211   VTKM_CONT typename ChangeOutputToInputMapType<NewOutputToInputMapType>::type
ChangeOutputToInputMapInvocation212   ChangeOutputToInputMap(NewOutputToInputMapType newOutputToInputMap) const
213   {
214     return typename ChangeOutputToInputMapType<NewOutputToInputMapType>::type(
215       this->Parameters, newOutputToInputMap, this->VisitArray);
216   }
217 
218   /// Defines a new \c Invocation type that is the same as this type except
219   /// with the \c VisitArrayType replaced.
220   ///
221   template <typename NewVisitArrayType>
222   struct ChangeVisitArrayType
223   {
224     using type = Invocation<ParameterInterface,
225                             ControlInterface,
226                             ExecutionInterface,
227                             InputDomainIndex,
228                             OutputToInputMapType,
229                             NewVisitArrayType>;
230   };
231 
232   /// Returns a new \c Invocation that is the same as this one except that the
233   /// \c VisitArray is replaced with that provided.
234   ///
235   template <typename NewVisitArrayType>
ChangeVisitArrayInvocation236   VTKM_CONT typename ChangeVisitArrayType<NewVisitArrayType>::type ChangeVisitArray(
237     NewVisitArrayType newVisitArray) const
238   {
239     return typename ChangeVisitArrayType<NewVisitArrayType>::type(
240       this->Parameters, this->OutputToInputMap, newVisitArray);
241   }
242 
243   /// A convenience alias for the input domain type.
244   ///
245   using InputDomainType =
246     typename ParameterInterface::template ParameterType<InputDomainIndex>::type;
247 
248   /// A convenience alias for the control signature tag of the input domain.
249   ///
250   using InputDomainTag = typename ControlInterface::template ParameterType<InputDomainIndex>::type;
251 
252   /// A convenience method to get the input domain object.
253   ///
254   VTKM_SUPPRESS_EXEC_WARNINGS
255   VTKM_EXEC_CONT
GetInputDomainInvocation256   const InputDomainType& GetInputDomain() const
257   {
258     return this->Parameters.template GetParameter<InputDomainIndex>();
259   }
260 
261   /// The state of an \c Invocation object holds the parameters of the
262   /// invocation. As well as the output to input map and the visit array.
263   ///
264   /// This is held by by value so that when we transfer the invocation object
265   /// over to CUDA it gets properly copied to the device. While we want to
266   /// hold by reference to reduce the number of copies, it is not possible
267   /// currently.
268   ParameterInterface Parameters;
269   OutputToInputMapType OutputToInputMap;
270   VisitArrayType VisitArray;
271 
272 private:
273   // Do not allow assignment of one Invocation to another. It is too expensive.
274   void operator=(const Invocation<ParameterInterface,
275                                   ControlInterface,
276                                   ExecutionInterface,
277                                   InputDomainIndex,
278                                   OutputToInputMapType,
279                                   VisitArrayType>&) = delete;
280 };
281 
282 /// Convenience function for creating an Invocation object.
283 ///
284 template <vtkm::IdComponent InputDomainIndex,
285           typename ControlInterface,
286           typename ExecutionInterface,
287           typename ParameterInterface,
288           typename OutputToInputMapType,
289           typename VisitArrayType>
290 VTKM_CONT vtkm::internal::Invocation<ParameterInterface,
291                                      ControlInterface,
292                                      ExecutionInterface,
293                                      InputDomainIndex,
294                                      OutputToInputMapType,
295                                      VisitArrayType>
make_Invocation(const ParameterInterface & params,ControlInterface,ExecutionInterface,OutputToInputMapType outputToInputMap,VisitArrayType visitArray)296 make_Invocation(const ParameterInterface& params,
297                 ControlInterface,
298                 ExecutionInterface,
299                 OutputToInputMapType outputToInputMap,
300                 VisitArrayType visitArray)
301 {
302   return vtkm::internal::Invocation<ParameterInterface,
303                                     ControlInterface,
304                                     ExecutionInterface,
305                                     InputDomainIndex,
306                                     OutputToInputMapType,
307                                     VisitArrayType>(params, outputToInputMap, visitArray);
308 }
309 template <vtkm::IdComponent InputDomainIndex,
310           typename ControlInterface,
311           typename ExecutionInterface,
312           typename ParameterInterface>
313 VTKM_CONT vtkm::internal::
314   Invocation<ParameterInterface, ControlInterface, ExecutionInterface, InputDomainIndex>
315   make_Invocation(const ParameterInterface& params,
316                   ControlInterface = ControlInterface(),
317                   ExecutionInterface = ExecutionInterface())
318 {
319   return vtkm::internal::make_Invocation<InputDomainIndex>(params,
320                                                            ControlInterface(),
321                                                            ExecutionInterface(),
322                                                            vtkm::internal::NullType(),
323                                                            vtkm::internal::NullType());
324 }
325 }
326 } // namespace vtkm::internal
327 
328 #endif //vtk_m_internal_Invocation_h
329