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