| 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 |