1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 
11 #include <vtkm/cont/ArrayRangeComputeTemplate.h>
12 
13 #include <vtkm/TypeList.h>
14 
15 namespace vtkm
16 {
17 namespace cont
18 {
19 
ThrowArrayRangeComputeFailed()20 void ThrowArrayRangeComputeFailed()
21 {
22   throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device.");
23 }
24 
25 #define VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(T, Storage)                                       \
26   VTKM_CONT                                                                               \
27   vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(                                 \
28     const vtkm::cont::ArrayHandle<T, Storage>& input, vtkm::cont::DeviceAdapterId device) \
29   {                                                                                       \
30     return detail::ArrayRangeComputeImpl(input, device);                                  \
31   }                                                                                       \
32   struct SwallowSemicolon
33 #define VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(T, N, Storage)            \
34   VTKM_CONT                                                         \
35   vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(           \
36     const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
37     vtkm::cont::DeviceAdapterId device)                             \
38   {                                                                 \
39     return detail::ArrayRangeComputeImpl(input, device);            \
40   }                                                                 \
41   struct SwallowSemicolon
42 
43 #define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(Storage)              \
44   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int8, Storage);                  \
45   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt8, Storage);                 \
46   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int16, Storage);                 \
47   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt16, Storage);                \
48   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int32, Storage);                 \
49   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt32, Storage);                \
50   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int64, Storage);                 \
51   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt64, Storage);                \
52   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float32, Storage);               \
53   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float64, Storage);               \
54   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(char, Storage);                        \
55   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(signed VTKM_UNUSED_INT_TYPE, Storage); \
56   VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(unsigned VTKM_UNUSED_INT_TYPE, Storage)
57 
58 #define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(N, Storage)                     \
59   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int8, N, Storage);                  \
60   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt8, N, Storage);                 \
61   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int16, N, Storage);                 \
62   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt16, N, Storage);                \
63   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int32, N, Storage);                 \
64   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt32, N, Storage);                \
65   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int64, N, Storage);                 \
66   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt64, N, Storage);                \
67   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, N, Storage);               \
68   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, N, Storage);               \
69   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(char, N, Storage);                        \
70   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \
71   VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage)
72 
73 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagBasic);
74 
75 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic);
76 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic);
77 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic);
78 
79 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA);
80 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA);
81 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA);
82 
83 VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagStride);
84 
85 VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates);
86 VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates);
87 
88 #undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T
89 #undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC
90 #undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T
91 #undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC
92 
93 // Special implementation for regular point coordinates, which are easy
94 // to determine.
95 VTKM_CONT
ArrayRangeCompute(const vtkm::cont::ArrayHandle<vtkm::Vec3f,vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag> & array,vtkm::cont::DeviceAdapterId)96 vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
97   const vtkm::cont::ArrayHandle<vtkm::Vec3f,
98                                 vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
99   vtkm::cont::DeviceAdapterId)
100 {
101   vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.ReadPortal();
102 
103   // In this portal we know that the min value is the first entry and the
104   // max value is the last entry.
105   vtkm::Vec3f minimum = portal.Get(0);
106   vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1);
107 
108   vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
109   rangeArray.Allocate(3);
110   vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
111   outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
112   outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
113   outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));
114 
115   return rangeArray;
116 }
117 
ArrayRangeCompute(const vtkm::cont::ArrayHandle<vtkm::Id,vtkm::cont::StorageTagIndex> & input,vtkm::cont::DeviceAdapterId)118 vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
119   const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
120   vtkm::cont::DeviceAdapterId)
121 {
122   vtkm::cont::ArrayHandle<vtkm::Range> result;
123   result.Allocate(1);
124   result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
125   return result;
126 }
127 
128 namespace
129 {
130 
131 using AllScalars = vtkm::TypeListBaseC;
132 
133 template <typename vtkm::IdComponent N>
134 struct VecTransform
135 {
136   template <typename T>
137   using type = vtkm::Vec<T, N>;
138 };
139 
140 template <vtkm::IdComponent N>
141 using AllVecOfSize = vtkm::ListTransform<AllScalars, VecTransform<N>::template type>;
142 
143 using AllVec = vtkm::ListAppend<AllVecOfSize<2>, AllVecOfSize<3>, AllVecOfSize<4>>;
144 
145 using AllTypes = vtkm::ListAppend<AllScalars, AllVec>;
146 
147 struct ComputeRangeFunctor
148 {
149   // Used with UnknownArrayHandle::CastAndCallForTypes
150   template <typename T, typename S>
operator ()vtkm::cont::__anond96b52940111::ComputeRangeFunctor151   void operator()(const vtkm::cont::ArrayHandle<T, S>& array,
152                   vtkm::cont::DeviceAdapterId device,
153                   vtkm::cont::ArrayHandle<vtkm::Range>& ranges) const
154   {
155     ranges = vtkm::cont::ArrayRangeCompute(array, device);
156   }
157 
158   // Used with vtkm::ListForEach to get components
159   template <typename T>
operator ()vtkm::cont::__anond96b52940111::ComputeRangeFunctor160   void operator()(T,
161                   const vtkm::cont::UnknownArrayHandle& array,
162                   vtkm::cont::DeviceAdapterId device,
163                   vtkm::cont::ArrayHandle<vtkm::Range>& ranges,
164                   bool& success) const
165   {
166     if (!success && array.IsBaseComponentType<T>())
167     {
168       vtkm::IdComponent numComponents = array.GetNumberOfComponentsFlat();
169       ranges.Allocate(numComponents);
170       auto rangePortal = ranges.WritePortal();
171       for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
172       {
173         vtkm::cont::ArrayHandleStride<T> componentArray = array.ExtractComponent<T>(componentI);
174         vtkm::cont::ArrayHandle<vtkm::Range> componentRange =
175           vtkm::cont::ArrayRangeCompute(componentArray, device);
176         rangePortal.Set(componentI, componentRange.ReadPortal().Get(0));
177       }
178       success = true;
179     }
180   }
181 };
182 
183 template <typename TList, typename Storage>
ComputeForStorage(const vtkm::cont::UnknownArrayHandle & array,vtkm::cont::DeviceAdapterId device)184 vtkm::cont::ArrayHandle<vtkm::Range> ComputeForStorage(const vtkm::cont::UnknownArrayHandle& array,
185                                                        vtkm::cont::DeviceAdapterId device)
186 {
187   vtkm::cont::ArrayHandle<vtkm::Range> ranges;
188   array.CastAndCallForTypes<TList, vtkm::List<Storage>>(ComputeRangeFunctor{}, device, ranges);
189   return ranges;
190 }
191 
192 } // anonymous namespace
193 
ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle & array,vtkm::cont::DeviceAdapterId device)194 vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle& array,
195                                                        vtkm::cont::DeviceAdapterId device)
196 {
197   // First, try fast-paths of precompiled array types common(ish) in fields.
198   try
199   {
200     if (array.IsStorageType<vtkm::cont::StorageTagBasic>())
201     {
202       return ComputeForStorage<AllTypes, vtkm::cont::StorageTagBasic>(array, device);
203     }
204     if (array.IsStorageType<vtkm::cont::StorageTagSOA>())
205     {
206       return ComputeForStorage<AllVec, vtkm::cont::StorageTagSOA>(array, device);
207     }
208     if (array.IsStorageType<vtkm::cont::StorageTagXGCCoordinates>())
209     {
210       return ComputeForStorage<vtkm::TypeListFieldVec3, vtkm::cont::StorageTagXGCCoordinates>(
211         array, device);
212     }
213     if (array.IsStorageType<vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>())
214     {
215       vtkm::cont::ArrayHandleUniformPointCoordinates uniformPoints;
216       array.AsArrayHandle(uniformPoints);
217       return vtkm::cont::ArrayRangeCompute(uniformPoints, device);
218     }
219     using CartesianProductStorage =
220       vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
221                                              vtkm::cont::StorageTagBasic,
222                                              vtkm::cont::StorageTagBasic>;
223     if (array.IsStorageType<CartesianProductStorage>())
224     {
225       return ComputeForStorage<vtkm::TypeListFieldVec3, CartesianProductStorage>(array, device);
226     }
227     if (array.IsStorageType<vtkm::cont::StorageTagConstant>())
228     {
229       return ComputeForStorage<AllTypes, vtkm::cont::StorageTagConstant>(array, device);
230     }
231     if (array.IsStorageType<vtkm::cont::StorageTagCounting>())
232     {
233       return ComputeForStorage<AllTypes, vtkm::cont::StorageTagCounting>(array, device);
234     }
235     if (array.IsStorageType<vtkm::cont::StorageTagIndex>())
236     {
237       return ArrayRangeCompute(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
238     }
239   }
240   catch (vtkm::cont::ErrorBadValue&)
241   {
242     // If a cast/call failed, try falling back to a more general implementation.
243   }
244 
245   vtkm::cont::ArrayHandle<vtkm::Range> ranges;
246   bool success = false;
247   vtkm::ListForEach(ComputeRangeFunctor{}, AllScalars{}, array, device, ranges, success);
248   return ranges;
249 }
250 
251 }
252 } // namespace vtkm::cont
253