GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/compiler/PointExecutable.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 290 336 86.3%
Functions: 102 135 75.6%
Branches: 326 706 46.2%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file compiler/PointExecutable.cc
5
6 #include "PointExecutable.h"
7 #include "Logger.h"
8
9 #include "openvdb_ax/ast/Scanners.h"
10 #include "openvdb_ax/Exceptions.h"
11 // @TODO refactor so we don't have to include PointComputeGenerator.h,
12 // but still have the functions defined in one place
13 #include "openvdb_ax/codegen/PointComputeGenerator.h"
14 #include "openvdb_ax/codegen/PointLeafLocalData.h"
15 #include "openvdb_ax/codegen/Codecs.h"
16
17 #include <openvdb/Types.h>
18
19 #include <openvdb/points/AttributeArray.h>
20 #include <openvdb/points/PointAttribute.h>
21 #include <openvdb/points/PointConversion.h> // ConversionTraits
22 #include <openvdb/points/PointDataGrid.h>
23 #include <openvdb/points/PointGroup.h>
24 #include <openvdb/points/PointMask.h>
25 #include <openvdb/points/PointMove.h>
26 #include <openvdb/points/PointDelete.h>
27
28 namespace openvdb {
29 OPENVDB_USE_VERSION_NAMESPACE
30 namespace OPENVDB_VERSION_NAME {
31
32 namespace ax {
33
34 struct PointExecutable::Settings
35 {
36 bool mCreateMissing = true;
37 size_t mGrainSize = 1;
38 std::string mGroup = "";
39 //IterType mValueIterator = IterType::ON;
40 bool mPostDelete = false;
41 AttributeBindings mBindings;
42 };
43
44 namespace {
45
46 /// @brief Point Kernel types
47 ///
48 using KernelValueFunctionPtr = std::add_pointer<codegen::PointKernelAttributeArray::Signature>::type;
49 using KernelBufferRangeFunctionPtr = std::add_pointer<codegen::PointKernelBufferRange::Signature>::type;
50 using PointLeafLocalData = codegen::codegen_internal::PointLeafLocalData;
51
52 #ifndef NDEBUG
53 inline bool supported(const ast::tokens::CoreType type)
54 {
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 switch (type) {
56 case ast::tokens::BOOL : return true;
57 case ast::tokens::CHAR : return true;
58 case ast::tokens::INT16 : return true;
59 case ast::tokens::INT32 : return true;
60 case ast::tokens::INT64 : return true;
61 case ast::tokens::FLOAT : return true;
62 case ast::tokens::DOUBLE : return true;
63 case ast::tokens::VEC2I : return true;
64 case ast::tokens::VEC2F : return true;
65 case ast::tokens::VEC2D : return true;
66 case ast::tokens::VEC3I : return true;
67 case ast::tokens::VEC3F : return true;
68 case ast::tokens::VEC3D : return true;
69 case ast::tokens::VEC4I : return true;
70 case ast::tokens::VEC4F : return true;
71 case ast::tokens::VEC4D : return true;
72 case ast::tokens::MAT3F : return true;
73 case ast::tokens::MAT3D : return true;
74 case ast::tokens::MAT4F : return true;
75 case ast::tokens::MAT4D : return true;
76 case ast::tokens::STRING : return true;
77 case ast::tokens::UNKNOWN :
78 default : return false;
79 }
80 }
81 #endif
82
83 5089 struct PointAttributeInfo
84 {
85 PointAttributeInfo(const std::string& name,
86 const ast::tokens::CoreType type,
87 const bool write)
88 5089 : mName(name)
89 , mType(type)
90
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
5089 , mWrite(write) {}
91 std::string mName;
92 ast::tokens::CoreType mType;
93 bool mWrite;
94 };
95
96 /// @brief Shared data for the parallel operator
97 struct OpData
98 {
99 KernelValueFunctionPtr mKernelAttributeArray;
100 KernelBufferRangeFunctionPtr mKernelBufferRange;
101 const CustomData* mCustomData;
102 const AttributeRegistry* mAttributeRegistry;
103 size_t mIterMode; // 0 = OFF, 1 = ON, 2 = ALL
104 const math::Transform* mTransform;
105 points::AttributeSet::Descriptor::GroupIndex mGroupIndex;
106 std::string mPositionAttribute;
107 std::pair<bool,bool> mPositionAccess;
108 bool mUseBufferKernel;
109 std::vector<PointAttributeInfo> mAttributeInfo;
110 };
111
112 /// @brief The arguments of the generated function
113 ///
114 struct PointFunctionArguments
115 {
116 using LeafT = points::PointDataTree::LeafNodeType;
117
118 /// @brief Base untyped handle struct for container storage
119 struct Handles
120 {
121 using UniquePtr = std::unique_ptr<Handles>;
122 virtual ~Handles() = default;
123 };
124
125 /// @brief A wrapper around a VDB Points Attribute Handle, allowing for
126 /// typed storage of a read or write handle. This is used for
127 /// automatic memory management and void pointer passing into the
128 /// generated point functions
129 template <typename ValueT>
130 struct ReadHandle final : public Handles
131 {
132 using UniquePtr = std::unique_ptr<ReadHandle<ValueT>>;
133 using HandleTraits = points::point_conversion_internal::ConversionTraits<ValueT>;
134 using HandleT = typename HandleTraits::Handle;
135 12 ReadHandle(const LeafT& leaf, const Index idx)
136 : mHandle(HandleTraits::handleFromLeaf(leaf, idx)) {}
137
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
24 ~ReadHandle() override final = default;
138 const std::unique_ptr<HandleT> mHandle;
139 };
140
141 template <typename ValueT>
142 struct WriteHandle final : public Handles
143 {
144 using UniquePtr = std::unique_ptr<WriteHandle<ValueT>>;
145 using HandleTraits = points::point_conversion_internal::ConversionTraits<ValueT>;
146 using HandleT = typename HandleTraits::WriteHandle;
147 372 WriteHandle(LeafT& leaf, const Index idx)
148
19/40
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 20 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 16 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 4 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 4 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 4 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 4 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 44 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 4 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✓ Branch 58 taken 12 times.
✗ Branch 59 not taken.
408 : mHandle(HandleTraits::writeHandleFromLeaf(leaf, idx)) {}
149
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
1152 ~WriteHandle() override final = default;
150 const std::unique_ptr<HandleT> mHandle;
151 };
152
153 ///////////////////////////////////////////////////////////////////////
154 ///////////////////////////////////////////////////////////////////////
155
156 1486 PointFunctionArguments(const OpData& data,
157 LeafT& leaf,
158 PointLeafLocalData* const leafLocalData)
159 1486 : mData(data)
160 , mAttributeSet(&leaf.attributeSet())
161 , mHandlesOrBuffers()
162 , mAttributeHandles()
163 , mVoidGroupHandles()
164 , mGroupHandles()
165 1486 , mLeafLocalData(leafLocalData)
166 {
167 // add attributes based on the order and existence in the attribute registry
168
2/2
✓ Branch 0 taken 10150 times.
✓ Branch 1 taken 1486 times.
11636 for (const auto& iter : mData.mAttributeInfo) {
169
1/2
✓ Branch 1 taken 10150 times.
✗ Branch 2 not taken.
10150 this->addAttributeHandle(leaf, iter.mName, iter.mType, iter.mWrite);
170 }
171
172 // add groups
173
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1461 times.
1486 const auto& map = mAttributeSet->descriptor().groupMap();
174
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1461 times.
1486 if (!map.empty()) {
175 // add all groups based on their offset within the attribute set - the offset can
176 // then be used as a key when retrieving groups from the linearized array, which
177 // is provided by the attribute set argument
178 std::map<size_t, std::string> orderedGroups;
179
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 25 times.
63 for (const auto& iter : map) {
180
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 orderedGroups[iter.second] = iter.first;
181 }
182
183 // add a handle at every offset up to and including the max offset. If the
184 // offset is not in use, we just use a null pointer as this will never be
185 // accessed
186 25 const size_t maxOffset = orderedGroups.crbegin()->first;
187 25 auto iter = orderedGroups.begin();
188
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 25 times.
63 for (size_t i = 0; i <= maxOffset; ++i) {
189
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (iter->first == i) {
190
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 this->addGroupWriteHandle(leaf, iter->second);
191 ++iter;
192 }
193 else {
194 // empty handle at this index
195 this->addNullGroupHandle();
196 }
197 }
198 }
199 1486 }
200
201 inline auto bindValueKernel()
202 {
203 using FunctionTraitsT = codegen::PointKernelAttributeArray::FunctionTraitsT;
204 using ReturnT = FunctionTraitsT::ReturnType;
205
206 64 return [&](const openvdb::Coord& origin, void* buffer, bool active, const size_t index) -> ReturnT {
207 64 mData.mKernelAttributeArray(static_cast<FunctionTraitsT::Arg<0>::Type>(mData.mCustomData),
208 reinterpret_cast<FunctionTraitsT::Arg<1>::Type>(origin.data()),
209 static_cast<FunctionTraitsT::Arg<2>::Type>(buffer),
210 static_cast<FunctionTraitsT::Arg<3>::Type>(active),
211 static_cast<FunctionTraitsT::Arg<4>::Type>(index),
212 static_cast<FunctionTraitsT::Arg<5>::Type>(nullptr/*mData.mVoidTransforms.data()*/),
213 static_cast<FunctionTraitsT::Arg<6>::Type>(mHandlesOrBuffers.data()),
214 static_cast<FunctionTraitsT::Arg<7>::Type>(mFlags.data()),
215 64 static_cast<FunctionTraitsT::Arg<8>::Type>(mAttributeSet),
216 static_cast<FunctionTraitsT::Arg<9>::Type>(mVoidGroupHandles.data()),
217 64 static_cast<FunctionTraitsT::Arg<10>::Type>(mLeafLocalData));
218 120 };
219 }
220
221 inline auto bindRangeKernel()
222 {
223 using FunctionTraitsT = codegen::PointKernelBufferRange::FunctionTraitsT;
224 using ReturnT = FunctionTraitsT::ReturnType;
225
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1430 times.
1430 assert(mData.mUseBufferKernel);
227
228 1430 return [&](const openvdb::Coord& origin, void* buffer, Index64* mask, const size_t size) -> ReturnT {
229 1430 mData.mKernelBufferRange(static_cast<FunctionTraitsT::Arg<0>::Type>(mData.mCustomData),
230 reinterpret_cast<FunctionTraitsT::Arg<1>::Type>(origin.data()),
231 static_cast<FunctionTraitsT::Arg<2>::Type>(buffer),
232 static_cast<FunctionTraitsT::Arg<3>::Type>(mask),
233 static_cast<FunctionTraitsT::Arg<4>::Type>(size),
234 static_cast<FunctionTraitsT::Arg<5>::Type>(2/*mData.mIterMode*/),
235 static_cast<FunctionTraitsT::Arg<6>::Type>(nullptr/*mData.mVoidTransforms.data()*/),
236 static_cast<FunctionTraitsT::Arg<7>::Type>(mHandlesOrBuffers.data()),
237 static_cast<FunctionTraitsT::Arg<8>::Type>(mFlags.data()),
238 1430 static_cast<FunctionTraitsT::Arg<9>::Type>(mAttributeSet),
239 static_cast<FunctionTraitsT::Arg<10>::Type>(mVoidGroupHandles.data()),
240 1430 static_cast<FunctionTraitsT::Arg<11>::Type>(mLeafLocalData));
241 2860 };
242 }
243
244 template <typename ValueT>
245 574 inline void addHandle(LeafT& leaf, const size_t pos)
246 {
247 574 uint64_t flag = 0;
248 const points::AttributeArray& array = leaf.constAttributeArray(pos);
249
2/2
✓ Branch 1 taken 285 times.
✓ Branch 2 taken 2 times.
574 if (array.isUniform()) flag |= uint64_t(1) << 63;
250
251 // @todo if the array is shared we should probably make it unique?
252
253 #if OPENVDB_ABI_VERSION_NUMBER >= 9
254
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 12 times.
574 if (mData.mUseBufferKernel) {
255 550 const_cast<points::AttributeArray&>(array).loadData();
256 const char* data = array.constDataAsByteArray();
257 550 void* ptr = static_cast<void*>(const_cast<char*>(data));
258 550 mHandlesOrBuffers.emplace_back(ptr);
259 const codegen::Codec* codec =
260
2/4
✓ Branch 2 taken 275 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 275 times.
✗ Branch 7 not taken.
1100 codegen::getCodec(ast::tokens::tokenFromTypeString(array.valueType()), array.codecType());
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
550 if (codec) flag |= codec->flag();
262 }
263 else {
264
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 typename ReadHandle<ValueT>::UniquePtr handle(new ReadHandle<ValueT>(leaf, Index(pos)));
265
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 mHandlesOrBuffers.emplace_back(handle->mHandle.get());
266
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 mAttributeHandles.emplace_back(std::move(handle));
267 }
268 #else
269 assert(!mData.mUseBufferKernel);
270 typename ReadHandle<ValueT>::UniquePtr handle(new ReadHandle<ValueT>(leaf, Index(pos)));
271 mHandlesOrBuffers.emplace_back(handle->mHandle.get());
272 mAttributeHandles.emplace_back(std::move(handle));
273 #endif
274
275 574 mFlags.emplace_back(flag);
276 }
277
278 template <typename ValueT>
279 19726 inline void addWriteHandle(LeafT& leaf, const size_t pos)
280 {
281 19726 uint64_t flag = 0;
282 19726 points::AttributeArray& array = leaf.attributeArray(pos);
283 19726 array.expand();
284
285 #if OPENVDB_ABI_VERSION_NUMBER >= 9
286
2/2
✓ Branch 0 taken 9491 times.
✓ Branch 1 taken 372 times.
19726 if (mData.mUseBufferKernel) {
287 18982 array.loadData();
288 const char* data = array.constDataAsByteArray();
289 18982 void* ptr = static_cast<void*>(const_cast<char*>(data));
290 18982 mHandlesOrBuffers.emplace_back(ptr);
291 const codegen::Codec* codec =
292
2/4
✓ Branch 2 taken 9491 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 9491 times.
✗ Branch 7 not taken.
37964 codegen::getCodec(ast::tokens::tokenFromTypeString(array.valueType()), array.codecType());
293
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9482 times.
18982 if (codec) flag |= codec->flag();
294
2/4
✓ Branch 1 taken 9491 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9491 times.
18982 assert(array.isDataLoaded() && !array.isUniform());
295 }
296 else {
297
1/2
✓ Branch 2 taken 168 times.
✗ Branch 3 not taken.
744 typename WriteHandle<ValueT>::UniquePtr handle(new WriteHandle<ValueT>(leaf, Index(pos)));
298
1/4
✓ Branch 1 taken 372 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
744 mHandlesOrBuffers.emplace_back(handle->mHandle.get());
299
1/2
✓ Branch 1 taken 372 times.
✗ Branch 2 not taken.
744 mAttributeHandles.emplace_back(std::move(handle));
300 }
301 #else
302 assert(!mData.mUseBufferKernel);
303 typename WriteHandle<ValueT>::UniquePtr handle(new WriteHandle<ValueT>(leaf, Index(pos)));
304 mHandlesOrBuffers.emplace_back(handle->mHandle.get());
305 mAttributeHandles.emplace_back(std::move(handle));
306 #endif
307
308 19726 mFlags.emplace_back(flag);
309 }
310
311 inline void addGroupHandle(const LeafT& leaf, const std::string& name)
312 {
313 assert(leaf.attributeSet().descriptor().hasGroup(name));
314 mGroupHandles.emplace_back(new points::GroupHandle(leaf.groupHandle(name)));
315 mVoidGroupHandles.emplace_back(static_cast<void*>(mGroupHandles.back().get()));
316 }
317
318 38 inline void addGroupWriteHandle(LeafT& leaf, const std::string& name)
319 {
320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 assert(leaf.attributeSet().descriptor().hasGroup(name));
321
1/2
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 mGroupHandles.emplace_back(new points::GroupWriteHandle(leaf.groupWriteHandle(name)));
322 38 mVoidGroupHandles.emplace_back(static_cast<void*>(mGroupHandles.back().get()));
323 38 }
324
325 inline void addNullGroupHandle() { mVoidGroupHandles.emplace_back(nullptr); }
326
327 inline void
328
1/2
✓ Branch 0 taken 10150 times.
✗ Branch 1 not taken.
10150 addAttributeHandle(LeafT& leaf, const std::string& name, const ast::tokens::CoreType type, const bool write)
329 {
330 // assert so the executer can be marked as noexcept (assuming nothing throws in compute)
331 assert(supported(type) && "Could not retrieve attribute handle from unsupported type");
332
20/22
✓ Branch 0 taken 1796 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 136 times.
✓ Branch 3 taken 1172 times.
✓ Branch 4 taken 396 times.
✓ Branch 5 taken 1121 times.
✓ Branch 6 taken 1592 times.
✓ Branch 7 taken 196 times.
✓ Branch 8 taken 196 times.
✓ Branch 9 taken 196 times.
✓ Branch 10 taken 300 times.
✓ Branch 11 taken 493 times.
✓ Branch 12 taken 520 times.
✓ Branch 13 taken 260 times.
✓ Branch 14 taken 264 times.
✓ Branch 15 taken 276 times.
✓ Branch 16 taken 248 times.
✓ Branch 17 taken 276 times.
✓ Branch 18 taken 256 times.
✓ Branch 19 taken 276 times.
✓ Branch 20 taken 180 times.
✗ Branch 21 not taken.
10150 switch (type) {
333 1796 case ast::tokens::BOOL : return this->addAttributeHandleTyped<bool>(leaf, name, write);
334 case ast::tokens::CHAR : return this->addAttributeHandleTyped<char>(leaf, name, write);
335 136 case ast::tokens::INT16 : return this->addAttributeHandleTyped<int16_t>(leaf, name, write);
336 1172 case ast::tokens::INT32 : return this->addAttributeHandleTyped<int32_t>(leaf, name, write);
337 396 case ast::tokens::INT64 : return this->addAttributeHandleTyped<int64_t>(leaf, name, write);
338 1121 case ast::tokens::FLOAT : return this->addAttributeHandleTyped<float>(leaf, name, write);
339 1592 case ast::tokens::DOUBLE : return this->addAttributeHandleTyped<double>(leaf, name, write);
340 196 case ast::tokens::VEC2I : return this->addAttributeHandleTyped<math::Vec2<int32_t>>(leaf, name, write);
341 196 case ast::tokens::VEC2F : return this->addAttributeHandleTyped<math::Vec2<float>>(leaf, name, write);
342 196 case ast::tokens::VEC2D : return this->addAttributeHandleTyped<math::Vec2<double>>(leaf, name, write);
343 300 case ast::tokens::VEC3I : return this->addAttributeHandleTyped<math::Vec3<int32_t>>(leaf, name, write);
344 493 case ast::tokens::VEC3F : return this->addAttributeHandleTyped<math::Vec3<float>>(leaf, name, write);
345 520 case ast::tokens::VEC3D : return this->addAttributeHandleTyped<math::Vec3<double>>(leaf, name, write);
346 260 case ast::tokens::VEC4I : return this->addAttributeHandleTyped<math::Vec4<int32_t>>(leaf, name, write);
347 264 case ast::tokens::VEC4F : return this->addAttributeHandleTyped<math::Vec4<float>>(leaf, name, write);
348 276 case ast::tokens::VEC4D : return this->addAttributeHandleTyped<math::Vec4<double>>(leaf, name, write);
349 248 case ast::tokens::MAT3F : return this->addAttributeHandleTyped<math::Mat3<float>>(leaf, name, write);
350 276 case ast::tokens::MAT3D : return this->addAttributeHandleTyped<math::Mat3<double>>(leaf, name, write);
351 256 case ast::tokens::MAT4F : return this->addAttributeHandleTyped<math::Mat4<float>>(leaf, name, write);
352 276 case ast::tokens::MAT4D : return this->addAttributeHandleTyped<math::Mat4<double>>(leaf, name, write);
353 180 case ast::tokens::STRING : return this->addAttributeHandleTyped<std::string>(leaf, name, write);
354 case ast::tokens::UNKNOWN :
355 default : return;
356 }
357 }
358
359 private:
360 template <typename ValueType>
361 inline void
362 20300 addAttributeHandleTyped(LeafT& leaf, const std::string& name, const bool write)
363 {
364 20300 const size_t pos = leaf.attributeSet().find(name);
365 //assert(!leaf.attributeSet().isShared(pos));
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10150 times.
20300 assert(pos != openvdb::points::AttributeSet::INVALID_POS);
367
2/2
✓ Branch 0 taken 9863 times.
✓ Branch 1 taken 287 times.
20300 if (write) this->addWriteHandle<ValueType>(leaf, pos);
368 574 else this->addHandle<ValueType>(leaf, pos);
369 }
370
371 private:
372 const OpData& mData;
373 const points::AttributeSet* const mAttributeSet;
374 std::vector<void*> mHandlesOrBuffers;
375 std::vector<Handles::UniquePtr> mAttributeHandles;
376 std::vector<uint64_t> mFlags;
377 std::vector<void*> mVoidGroupHandles;
378 std::vector<points::GroupHandle::UniquePtr> mGroupHandles;
379 PointLeafLocalData* const mLeafLocalData;
380 };
381
382
383 ///////////////////////////////////////////////////////////////////////////
384 ///////////////////////////////////////////////////////////////////////////
385
386
387 template<typename FilterT = openvdb::points::NullFilter>
388 struct PointExecuterDeformer
389 {
390
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 PointExecuterDeformer(const std::string& positionAttribute,
391 const FilterT& filter = FilterT())
392 : mFilter(filter)
393 , mPws(nullptr)
394
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 , mPositionAttribute(positionAttribute) {}
395
396
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
20 PointExecuterDeformer(const PointExecuterDeformer& other)
397 : mFilter(other.mFilter)
398 , mPws(nullptr)
399
2/8
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
20 , mPositionAttribute(other.mPositionAttribute) {}
400
401 template <typename LeafT>
402 40 void reset(const LeafT& leaf, const size_t)
403 {
404 mFilter.reset(leaf);
405
1/2
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
40 mPws.reset(new points::AttributeHandle<Vec3f>(leaf.constAttributeArray(mPositionAttribute)));
406 }
407
408 template <typename IterT>
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
56 void apply(Vec3d& position, const IterT& iter) const
410 {
411 if (mFilter.valid(iter)) {
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
56 assert(mPws);
413 56 position = Vec3d(mPws->get(*iter));
414 }
415 }
416
417 FilterT mFilter;
418 points::AttributeHandle<Vec3f>::UniquePtr mPws;
419 const std::string& mPositionAttribute;
420 };
421
422 /// @brief VDB Points executer for a compiled function pointer
423 struct PointExecuterOp
424 {
425 using LeafManagerT = openvdb::tree::LeafManager<openvdb::points::PointDataTree>;
426 using LeafNode = openvdb::points::PointDataTree::LeafNodeType;
427 using GroupFilter = openvdb::points::GroupFilter;
428
429 PointExecuterOp(const OpData& data,
430 std::vector<PointLeafLocalData::UniquePtr>& leafLocalData)
431 748 : mData(data)
432 748 , mLeafLocalData(leafLocalData) {}
433
434 template<typename FilterT = openvdb::points::NullFilter>
435 inline std::unique_ptr<points::AttributeWriteHandle<Vec3f>>
436 24 initPositions(LeafNode& leaf, const FilterT& filter = FilterT()) const
437 {
438
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
72 points::AttributeHandle<Vec3f> positions(leaf.constAttributeArray("P"));
439 std::unique_ptr<points::AttributeWriteHandle<Vec3f>>
440
3/6
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
24 pws(new points::AttributeWriteHandle<Vec3f>(leaf.attributeArray(mData.mPositionAttribute)));
441
442
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 12 times.
60 for (auto iter = leaf.beginIndexAll(filter); iter; ++iter) {
443 36 const Index idx = *iter;
444
3/6
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
36 const openvdb::Vec3f pos = positions.get(idx) + iter.getCoord().asVec3s();
445
3/8
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
36 pws->set(idx, mData.mTransform->indexToWorld(pos));
446 }
447
448 24 return pws;
449 }
450
451 1486 void operator()(LeafNode& leaf, size_t idx) const
452 {
453 1486 auto& leafLocalData = mLeafLocalData[idx];
454 1486 leafLocalData.reset(new PointLeafLocalData(leaf.getLastValue()));
455
456 1486 const bool group = mData.mGroupIndex.first != points::AttributeSet::INVALID_POS;
457
458 // if we are using position we need to initialise the world space storage
459 1486 std::unique_ptr<points::AttributeWriteHandle<Vec3f>> pws;
460
3/4
✓ Branch 0 taken 1474 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1474 times.
1486 if (mData.mPositionAccess.first || mData.mPositionAccess.second) {
461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (group) {
462 const GroupFilter filter(mData.mGroupIndex);
463 pws = this->initPositions(leaf, filter);
464 }
465 else {
466
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 pws = this->initPositions(leaf);
467 }
468 }
469
470
1/2
✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
2972 PointFunctionArguments args(mData, leaf, leafLocalData.get());
471
1/2
✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
1486 void* buffer = static_cast<void*>(leaf.buffer().data());
472
473
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1478 times.
1486 if (group) {
474 8 const auto kernel = args.bindValueKernel();
475
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const GroupFilter filter(mData.mGroupIndex);
476
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 auto iter = leaf.beginIndex<LeafNode::ValueAllCIter, GroupFilter>(filter);
477
4/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
12 for (; iter; ++iter) kernel(leaf.origin(), buffer, /*active*/true, *iter);
478 }
479
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1430 times.
1478 else if (!mData.mUseBufferKernel) {
480 48 const auto kernel = args.bindValueKernel();
481 auto iter = leaf.beginIndexAll();
482
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 48 times.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
108 for (; iter; ++iter) kernel(leaf.origin(), buffer, /*active*/true, *iter);
483 }
484 else {
485
1/2
✓ Branch 1 taken 1430 times.
✗ Branch 2 not taken.
1430 const auto kernel = args.bindRangeKernel();
486 Index64* masks = &(leaf.getValueMask().template getWord<Index64>(0));
487
1/2
✓ Branch 1 taken 1430 times.
✗ Branch 2 not taken.
1430 kernel(leaf.origin(), buffer, masks, size_t(LeafNode::NUM_VOXELS));
488 }
489
490 // if not writing to position (i.e. post sorting) collapse the temporary attribute
491
492
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1474 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 10 times.
1486 if (pws && !mData.mPositionAccess.second) {
493
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pws->collapse();
494 pws.reset();
495 }
496
497 // as multiple groups can be stored in a single array, attempt to compact the
498 // arrays directly so that we're not trying to call compact multiple times
499 // unsuccessfully
500
1/2
✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
1486 leafLocalData->compact();
501 1486 }
502
503 void operator()(const LeafManagerT::LeafRange& range) const
504 {
505 for (auto leaf = range.begin(); leaf; ++leaf) {
506 (*this)(*leaf, leaf.pos());
507 }
508 }
509
510 private:
511 const OpData& mData;
512 std::vector<PointLeafLocalData::UniquePtr>& mLeafLocalData;
513 };
514
515 92 inline NamePair typePairFromToken(const ast::tokens::CoreType type)
516 {
517
9/22
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 26 times.
✗ Branch 21 not taken.
92 switch (type) {
518 case ast::tokens::BOOL : return points::TypedAttributeArray<bool>::attributeType();
519 case ast::tokens::CHAR : return points::TypedAttributeArray<char>::attributeType();
520 2 case ast::tokens::INT16 : return points::TypedAttributeArray<int16_t>::attributeType();
521 20 case ast::tokens::INT32 : return points::TypedAttributeArray<int32_t>::attributeType();
522 2 case ast::tokens::INT64 : return points::TypedAttributeArray<int64_t>::attributeType();
523 21 case ast::tokens::FLOAT : return points::TypedAttributeArray<float>::attributeType();
524 2 case ast::tokens::DOUBLE : return points::TypedAttributeArray<double>::attributeType();
525 case ast::tokens::VEC2I : return points::TypedAttributeArray<math::Vec2<int32_t>>::attributeType();
526 case ast::tokens::VEC2F : return points::TypedAttributeArray<math::Vec2<float>>::attributeType();
527 case ast::tokens::VEC2D : return points::TypedAttributeArray<math::Vec2<double>>::attributeType();
528 4 case ast::tokens::VEC3I : return points::TypedAttributeArray<math::Vec3<int32_t>>::attributeType();
529 13 case ast::tokens::VEC3F : return points::TypedAttributeArray<math::Vec3<float>>::attributeType();
530 2 case ast::tokens::VEC3D : return points::TypedAttributeArray<math::Vec3<double>>::attributeType();
531 case ast::tokens::VEC4I : return points::TypedAttributeArray<math::Vec4<int32_t>>::attributeType();
532 case ast::tokens::VEC4F : return points::TypedAttributeArray<math::Vec4<float>>::attributeType();
533 case ast::tokens::VEC4D : return points::TypedAttributeArray<math::Vec4<double>>::attributeType();
534 case ast::tokens::MAT3F : return points::TypedAttributeArray<math::Mat3<float>>::attributeType();
535 case ast::tokens::MAT3D : return points::TypedAttributeArray<math::Mat3<double>>::attributeType();
536 case ast::tokens::MAT4F : return points::TypedAttributeArray<math::Mat4<float>>::attributeType();
537 case ast::tokens::MAT4D : return points::TypedAttributeArray<math::Mat4<double>>::attributeType();
538 26 case ast::tokens::STRING : return points::StringAttributeArray::attributeType();
539 case ast::tokens::UNKNOWN :
540 default : {
541 return NamePair();
542 }
543 }
544 }
545
546 751 void processAttributes(points::PointDataGrid& grid,
547 std::vector<PointAttributeInfo>& attributeInfo,
548 std::pair<bool,bool>& positionAccess,
549 std::string& posWS,
550 const AttributeRegistry& registry,
551 const AttributeBindings& bindings,
552 const bool createMissing,
553 Logger& logger)
554 {
555 const auto leafIter = grid.tree().cbeginLeaf();
556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751 times.
751 assert(leafIter);
557
558 751 attributeInfo.reserve(registry.data().size());
559
560 // append attributes
561
562
2/2
✓ Branch 0 taken 5089 times.
✓ Branch 1 taken 749 times.
5838 for (const auto& iter : registry.data()) {
563 // get the corresponding point attributes
564 const std::string* nameptr = bindings.dataNameBoundTo(iter.name());
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5089 times.
10087 if (!nameptr) continue;
566 const std::string& name = *nameptr;
567 const points::AttributeSet::Descriptor& desc = leafIter->attributeSet().descriptor();
568
569 // handle position separately as we need to create temp storage during execution
570 // create temporary world space position attribute if P is being accessed
571 // @todo should avoid actually adding this attribute to the tree as its temporary
572
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5083 times.
5089 if (name == "P") {
573 positionAccess = {iter.reads(), iter.writes()};
574
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 posWS = desc.uniqueName("__P");
575
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 points::appendAttribute<openvdb::Vec3f>(grid.tree(), posWS);
576
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 attributeInfo.emplace_back(posWS, ast::tokens::VEC3F, positionAccess.second);
577 6 continue;
578 }
579 // add the data name to the attribute info
580
1/2
✓ Branch 1 taken 5083 times.
✗ Branch 2 not taken.
5083 attributeInfo.emplace_back(name, iter.type(), iter.writes());
581
582
1/2
✓ Branch 1 taken 5083 times.
✗ Branch 2 not taken.
5083 const size_t pos = desc.find(name);
583
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5081 times.
5083 if (!createMissing && pos == points::AttributeSet::INVALID_POS) {
584
6/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 2 times.
14 logger.error("Attribute \"" + name + "\" does not exist on grid \"" + grid.getName() + "\"."
585
8/14
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 1 times.
8 + (name != iter.name() ? "[bound to \"" + iter.name() + " \"]" : ""));
586 continue;
587 }
588
589
2/2
✓ Branch 0 taken 4992 times.
✓ Branch 1 taken 89 times.
5081 if (pos != points::AttributeSet::INVALID_POS) {
590
1/2
✓ Branch 1 taken 4992 times.
✗ Branch 2 not taken.
4992 const points::AttributeArray* const array = leafIter->attributeSet().getConst(pos);
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4992 times.
4992 assert(array);
592
2/4
✓ Branch 1 taken 4992 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4992 times.
4992 if (array->stride() > 1) {
593 logger.warning("Attribute \"" + name + (name != iter.name() ? "\" [bound to \"" + iter.name() + "\"]" : "\"")
594 + " on grid \"" + grid.getName() + "\"is a strided (array) attribute. "
595 "Reading or writing to this attribute with @" + name + " will only access the first element.");
596 }
597
598
1/2
✓ Branch 1 taken 4992 times.
✗ Branch 2 not taken.
4992 const NamePair& type = desc.type(pos);
599 const ast::tokens::CoreType typetoken =
600 4992 ast::tokens::tokenFromTypeString(type.first);
601
602
3/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 4928 times.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
5056 if (typetoken != iter.type() &&
603
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
128 !(type.second == "str" && iter.type() == ast::tokens::STRING)) {
604 logger.error("Mismatching attributes types. Attribute \"" + name +
605 (name != iter.name() ? "\" [bound to \"" + iter.name() + "\"]" : "\"") +
606 " on grid \"" + grid.getName() + "\" exists of type \"" + type.first +
607 "\" but has been accessed with type \"" +
608 ast::tokens::typeStringFromToken(iter.type()) + "\"");
609 }
610 4992 continue;
611 }
612
613 assert(supported(iter.type()));
614
1/2
✓ Branch 1 taken 89 times.
✗ Branch 2 not taken.
178 const NamePair type = typePairFromToken(iter.type());
615
1/2
✓ Branch 1 taken 89 times.
✗ Branch 2 not taken.
89 points::appendAttribute(grid.tree(), name, type);
616 }
617 749 }
618
619 749 bool checkCodecs(const points::AttributeSet::Descriptor& desc,
620 const AttributeRegistry& registry,
621 const AttributeBindings& bindings,
622 const std::string& posWS)
623 {
624
2/2
✓ Branch 0 taken 4999 times.
✓ Branch 1 taken 725 times.
5724 for (const auto& iter : registry.data()) {
625 // no support for strings yet (we should just use the cbind)
626
2/2
✓ Branch 0 taken 4975 times.
✓ Branch 1 taken 24 times.
4999 if (iter.type() == ast::tokens::STRING) return false;
627
628 // if this type has no possible codec, continue
629
1/2
✓ Branch 1 taken 4975 times.
✗ Branch 2 not taken.
4975 const auto* codecs = codegen::getTypeSupportedCodecs(iter.type());
630
2/2
✓ Branch 0 taken 4151 times.
✓ Branch 1 taken 824 times.
5780 if (!codecs) continue;
631
632
1/2
✓ Branch 1 taken 824 times.
✗ Branch 2 not taken.
824 std::string name = iter.name();
633 const std::string* nameptr = bindings.dataNameBoundTo(name);
634
1/2
✓ Branch 0 taken 824 times.
✗ Branch 1 not taken.
824 if (nameptr) name = *nameptr;
635 else if (name == "P") name = posWS;
636
637
2/4
✓ Branch 1 taken 824 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 824 times.
✗ Branch 5 not taken.
824 const std::string& codec = desc.type(desc.find(name)).second;
638
639 // null codecs can be ignored
640
3/4
✓ Branch 1 taken 824 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 805 times.
✓ Branch 5 taken 19 times.
824 if (codec == std::string(points::NullCodec::name())) continue;
641
642 // unknown codec in use, fall back to cbinding
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (codecs->find(codec) == codecs->cend()) return false;
644 }
645
646 725 return true;
647 }
648
649 } // anonymous namespace
650
651 757 PointExecutable::PointExecutable(const std::shared_ptr<const llvm::LLVMContext>& context,
652 const std::shared_ptr<const llvm::ExecutionEngine>& engine,
653 const AttributeRegistry::ConstPtr& attributeRegistry,
654 const CustomData::ConstPtr& customData,
655 const std::unordered_map<std::string, uint64_t>& functions,
656 757 const ast::Tree& ast)
657 : mContext(context)
658 , mExecutionEngine(engine)
659 , mAttributeRegistry(attributeRegistry)
660 , mCustomData(customData)
661 , mFunctionAddresses(functions)
662
2/4
✓ Branch 1 taken 757 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 757 times.
✗ Branch 5 not taken.
757 , mSettings(new Settings)
663 {
664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 757 times.
757 assert(mContext);
665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 757 times.
757 assert(mExecutionEngine);
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 757 times.
757 assert(mAttributeRegistry);
667
668 // parse the AST for known functions which require pre/post processing
669
2/4
✓ Branch 1 taken 757 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 757 times.
✗ Branch 5 not taken.
757 mSettings->mPostDelete = ast::callsFunction(ast, "deletepoint");
670
671 // Set up the default attribute bindings
672
2/2
✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 757 times.
5842 for (const auto& iter : mAttributeRegistry->data()) {
673
1/2
✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
5085 mSettings->mBindings.set(iter.name(), iter.name());
674 }
675 757 }
676
677 PointExecutable::PointExecutable(const PointExecutable& other)
678 : mContext(other.mContext)
679 , mExecutionEngine(other.mExecutionEngine)
680 , mAttributeRegistry(other.mAttributeRegistry)
681 , mCustomData(other.mCustomData)
682 , mFunctionAddresses(other.mFunctionAddresses)
683 , mSettings(new Settings(*other.mSettings)) {
684 }
685
686 757 PointExecutable::~PointExecutable() {}
687
688 751 void PointExecutable::execute(openvdb::points::PointDataGrid& grid) const
689 {
690 using LeafManagerT = openvdb::tree::LeafManager<openvdb::points::PointDataTree>;
691
692 Logger* logger;
693 748 std::unique_ptr<Logger> log;
694 if (true) {
695 /// @note This branch exists for forwards compatibility with upcoming
696 /// changes to allow a logger to be provided to the executables
697
3/8
✓ Branch 3 taken 751 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 751 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
3007 log.reset(new Logger([](const std::string& error) {
698
1/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
12 OPENVDB_THROW(AXExecutionError, error);
699
2/4
✓ Branch 1 taken 751 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 751 times.
✗ Branch 5 not taken.
751 }));
700 logger = log.get();
701 }
702
703 const auto leafIter = grid.tree().cbeginLeaf();
704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751 times.
751 if (!leafIter) {
705
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
3 logger->warning("PointDataGrid \"" + grid.getName() + "\" is empty.");
706 return;
707 }
708
709 // Initialize the shared op data
710 748 OpData data;
711
712 // create any missing attributes and handle temp ws position storage
713 data.mPositionAccess = {false, false};
714 751 processAttributes(grid, data.mAttributeInfo, data.mPositionAccess, data.mPositionAttribute,
715 751 *mAttributeRegistry, mSettings->mBindings,
716
2/2
✓ Branch 1 taken 749 times.
✓ Branch 2 taken 2 times.
751 mSettings->mCreateMissing, *logger);
717
718 749 data.mKernelAttributeArray =
719 reinterpret_cast<KernelValueFunctionPtr>
720
2/4
✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 749 times.
✗ Branch 5 not taken.
1498 (mFunctionAddresses.at(codegen::PointKernelAttributeArray::getDefaultName()));
721 749 data.mKernelBufferRange =
722 reinterpret_cast<KernelBufferRangeFunctionPtr>
723
4/6
✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 749 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 745 times.
1498 (mFunctionAddresses.at(codegen::PointKernelBufferRange::getDefaultName()));
724 749 data.mTransform = &grid.transform();
725 749 data.mCustomData = mCustomData.get();
726 749 data.mGroupIndex.first = openvdb::points::AttributeSet::INVALID_POS;
727
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 745 times.
749 data.mAttributeRegistry = mAttributeRegistry.get();
728 //data.mPositionAccess = mAttributeRegistry->accessPattern("P", ast::tokens::VEC3F);
729
730 // init the internal dead group if necessary
731
732
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 745 times.
749 if (mSettings->mPostDelete) {
733 // @todo This group is hard coded in the deletepoint function call - we
734 // should perhaps instead pass in a unique group string to the point kernel
735
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
8 if (leafIter->attributeSet().descriptor().hasGroup("__ax_dead")) {
736 logger->warning("Input points grid \"" + grid.getName() + "\" contains the "
737 "internal point group \"__ax_dead\" which is used for deleting points. "
738 "points in this group may also be removed.");
739 }
740 else {
741
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 points::appendGroup(grid.tree(), "__ax_dead");
742 }
743 }
744
745 const bool usingGroup = !mSettings->mGroup.empty();
746
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 746 times.
749 if (usingGroup) {
747
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
3 if (!leafIter->attributeSet().descriptor().hasGroup(mSettings->mGroup)) {
748
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
4 logger->error("Requested point group \"" + mSettings->mGroup +
749
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
7 "\" on grid \"" + grid.getName() + "\" does not exist.");
750 }
751 else {
752 data.mGroupIndex =
753
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 leafIter->attributeSet().groupIndex(mSettings->mGroup);
754 }
755 }
756
757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 748 times.
748 if (logger->hasError()) return;
758
759 // Compute whether we can use the accelerated kernel
760 // @note Assumes attributes are valid (i.e. has errored out if they are not)
761
762 #if OPENVDB_ABI_VERSION_NUMBER >= 9
763
2/2
✓ Branch 0 taken 746 times.
✓ Branch 1 taken 2 times.
748 if (!usingGroup) {
764 const auto& desc = leafIter->attributeSet().descriptor();
765 746 data.mUseBufferKernel = checkCodecs(desc, *mAttributeRegistry,
766
1/2
✓ Branch 1 taken 746 times.
✗ Branch 2 not taken.
746 mSettings->mBindings,
767 data.mPositionAttribute);
768 }
769 else {
770 // if a group has been specified we can't use the buffer range yet
771 2 data.mUseBufferKernel = false;
772 }
773 #else
774 // can't access data buffers until ABI >= 9
775 data.mUseBufferKernel = false;
776 #endif
777
778 // execute
779
780
1/2
✓ Branch 1 taken 748 times.
✗ Branch 2 not taken.
1496 LeafManagerT leafManager(grid.tree());
781
2/4
✓ Branch 1 taken 748 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 748 times.
✗ Branch 5 not taken.
1496 std::vector<PointLeafLocalData::UniquePtr> leafLocalData(leafManager.leafCount());
782 748 const bool threaded = mSettings->mGrainSize > 0;
783
784 PointExecuterOp executerOp(data, leafLocalData);
785
1/2
✓ Branch 1 taken 748 times.
✗ Branch 2 not taken.
748 leafManager.foreach(executerOp, threaded, mSettings->mGrainSize);
786
787 // Check to see if any new data has been added and apply it accordingly
788
789 std::set<std::string> groups;
790 bool newStrings = false;
791
792 {
793 points::StringMetaInserter
794
2/4
✓ Branch 1 taken 748 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 748 times.
✗ Branch 5 not taken.
1496 inserter(leafIter->attributeSet().descriptorPtr()->getMetadata());
795
2/2
✓ Branch 0 taken 1486 times.
✓ Branch 1 taken 748 times.
2234 for (const auto& leafData : leafLocalData) {
796
1/2
✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
1486 leafData->getGroups(groups);
797
1/2
✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
1486 newStrings |= leafData->insertNewStrings(inserter);
798 }
799 }
800
801 // append and copy over newly created groups
802 // @todo We should just be able to steal the arrays and compact
803 // groups but the API for this isn't very nice at the moment
804
805
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 748 times.
759 for (const auto& name : groups) {
806
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 points::appendGroup(grid.tree(), name);
807 }
808
809 // add new groups and set strings
810
811
1/2
✓ Branch 1 taken 748 times.
✗ Branch 2 not taken.
748 leafManager.foreach(
812 1486 [&groups, &leafLocalData, newStrings] (auto& leaf, size_t idx) {
813
814 PointLeafLocalData::UniquePtr& leafData = leafLocalData[idx];
815
816
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1486 times.
1499 for (const auto& name : groups) {
817
818 // Attempt to get the group handle out of the leaf local data form this
819 // leaf. This may not exist as although all of the unique set are appended
820 // to the tree (above), not every leaf may have been directly touched
821 // by every new group. Some leaf nodes may not require any bit mask copying
822
823 13 points::GroupWriteHandle* tmpHandle = leafData->get(name);
824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tmpHandle) continue;
825
826
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 points::GroupWriteHandle handle = leaf.groupWriteHandle(name);
827
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 if (tmpHandle->isUniform()) {
828
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 handle.collapse(tmpHandle->get(0));
829 }
830 else {
831 const openvdb::Index size = tmpHandle->size();
832
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (openvdb::Index i = 0; i < size; ++i) {
833
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 handle.set(i, tmpHandle->get(i));
834 }
835 }
836 }
837
838
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1438 times.
1486 if (newStrings) {
839 48 const MetaMap& metadata = leaf.attributeSet().descriptor().getMetadata();
840 const PointLeafLocalData::StringArrayMap& stringArrayMap = leafData->getStringArrayMap();
841
842
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 48 times.
196 for (const auto& arrayIter : stringArrayMap) {
843 148 points::StringAttributeWriteHandle::Ptr handle =
844
1/2
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
148 points::StringAttributeWriteHandle::create(*(arrayIter.first), metadata);
845
846
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 148 times.
333 for (const auto& iter : arrayIter.second) {
847
1/2
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
185 handle->set(static_cast<Index>(iter.first), iter.second);
848 }
849 }
850 }
851 1486 }, threaded, mSettings->mGrainSize);
852
853
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 744 times.
748 if (data.mPositionAccess.second) {
854 // if position is writable, sort the points
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (usingGroup) {
856 openvdb::points::GroupFilter filter(data.mGroupIndex);
857 PointExecuterDeformer<openvdb::points::GroupFilter> deformer(data.mPositionAttribute, filter);
858 openvdb::points::movePoints(grid, deformer);
859 }
860 else {
861 PointExecuterDeformer<> deformer(data.mPositionAttribute);
862
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 openvdb::points::movePoints(grid, deformer);
863 }
864 }
865
866
3/4
✓ Branch 0 taken 742 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 742 times.
748 if (data.mPositionAccess.first || data.mPositionAccess.second) {
867 // remove temporary world space storage
868
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 points::dropAttribute(grid.tree(), data.mPositionAttribute);
869 }
870
871
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 744 times.
748 if (mSettings->mPostDelete) {
872
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 points::deleteFromGroup(grid.tree(), "__ax_dead", false, /*drop=*/true);
873 }
874 }
875
876
877 /////////////////////////////////////////////
878 /////////////////////////////////////////////
879
880
881 725 void PointExecutable::setCreateMissing(const bool flag)
882 {
883 725 mSettings->mCreateMissing = flag;
884 725 }
885
886 bool PointExecutable::getCreateMissing() const
887 {
888 return mSettings->mCreateMissing;
889 }
890
891 // void PointExecutable::setValueIterator(const PointExecutable::IterType& iter)
892 // {
893 // mSettings->mValueIterator = iter;
894 // }
895
896 // PointExecutable::IterType PointExecutable::getValueIterator() const
897 // {
898 // return mSettings->mValueIterator;
899 // }
900
901 void PointExecutable::setGrainSize(const size_t grain)
902 {
903 mSettings->mGrainSize = grain;
904 }
905
906 size_t PointExecutable::getGrainSize() const
907 {
908 return mSettings->mGrainSize;
909 }
910
911 1 void PointExecutable::setGroupExecution(const std::string& group)
912 {
913 1 mSettings->mGroup = group;
914 1 }
915
916 const std::string& PointExecutable::getGroupExecution() const
917 {
918 return mSettings->mGroup;
919 }
920
921 19 void PointExecutable::setAttributeBindings(const AttributeBindings& bindings)
922 {
923 //@todo: warn when inferred P, Cd, N etc are bound they default to vec3f
924
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
38 for (const auto& binding : bindings.axToDataMap()) {
925 19 mSettings->mBindings.set(binding.first, binding.second);
926 }
927
928 // check the registry to make sure everything is bound
929
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18 times.
53 for (const auto& access : mAttributeRegistry->data()) {
930 if (!mSettings->mBindings.isBoundAXName(access.name())) {
931 if (bindings.isBoundDataName(access.name())) {
932
6/14
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
8 OPENVDB_THROW(AXExecutionError, "AX attribute \"@"
933 + access.name() + "\" not bound to any point attribute."
934 " Point attribute \"" + access.name() + "\" bound to \"@"
935 + *bindings.axNameBoundTo(access.name()) + "\".");
936 }
937 else {
938 // rebind to itself as it may have been unbound
939 // by a previous set call
940 1 mSettings->mBindings.set(access.name(), access.name());
941 }
942 }
943 }
944 18 }
945
946 1 const AttributeBindings& PointExecutable::getAttributeBindings() const
947 {
948 1 return mSettings->mBindings;
949 }
950
951 //
952
953 3 bool PointExecutable::usesAcceleratedKernel(const points::PointDataTree& tree) const
954 {
955
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (tree.empty()) return true;
956
957 // deep copy the Descriptor
958
959 const auto leafIter = tree.cbeginLeaf();
960 points::AttributeSet::Descriptor::Ptr desc(
961
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 new points::AttributeSet::Descriptor(leafIter->attributeSet().descriptor()));
962
963 // add any attributes which don't exist for the codec check
964
965
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 for (const auto& iter : mAttributeRegistry->data()) {
966 // get the corresponding point attributes
967 const std::string* nameptr = mSettings->mBindings.dataNameBoundTo(iter.name());
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!nameptr) continue;
969 const std::string& name = *nameptr;
970
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
15 if (points::AttributeSet::INVALID_POS == desc->find(name)) {
971 const NamePair type = typePairFromToken(iter.type());
972 desc = desc->duplicateAppend(name, type);
973 }
974 }
975
976 // If P is being written or read from it is implicitly converted
977 // to an uncompressed attribute, so make sure P is not compressed
978
979
6/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
9 desc = desc->duplicateDrop({desc->find("P")});
980
3/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
6 desc = desc->duplicateAppend("P", typePairFromToken(ast::tokens::CoreType::VEC3F));
981
982
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
6 return checkCodecs(*desc, *mAttributeRegistry,
983
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 mSettings->mBindings, "P");
984 }
985
986
987 } // namespace ax
988 } // namespace OPENVDB_VERSION_NAME
989 } // namespace openvdb
990
991