1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file points/AttributeArray.cc
5
6 #include "AttributeArray.h"
7 #include <map>
8
9 namespace openvdb {
10 OPENVDB_USE_VERSION_NAMESPACE
11 namespace OPENVDB_VERSION_NAME {
12 namespace points {
13
14
15 ////////////////////////////////////////
16
17
18 namespace {
19
20 using AttributeFactoryMap = std::map<NamePair, AttributeArray::FactoryMethod>;
21
22 struct LockedAttributeRegistry
23 {
24 tbb::spin_mutex mMutex;
25 AttributeFactoryMap mMap;
26 };
27
28 // Global function for accessing the registry
29 LockedAttributeRegistry*
getAttributeRegistry()30 getAttributeRegistry()
31 {
32 static LockedAttributeRegistry registry;
33 return ®istry;
34 }
35
36 } // unnamed namespace
37
38
39 ////////////////////////////////////////
40
41 // AttributeArray::ScopedRegistryLock implementation
42
ScopedRegistryLock()43 AttributeArray::ScopedRegistryLock::ScopedRegistryLock()
44 : lock(getAttributeRegistry()->mMutex)
45 {
46 }
47
48
49 ////////////////////////////////////////
50
51 // AttributeArray implementation
52
53
54 #if OPENVDB_ABI_VERSION_NUMBER >= 7
AttributeArray(const AttributeArray & rhs)55 AttributeArray::AttributeArray(const AttributeArray& rhs)
56 : AttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
57 {
58 }
59
60
AttributeArray(const AttributeArray & rhs,const tbb::spin_mutex::scoped_lock &)61 AttributeArray::AttributeArray(const AttributeArray& rhs, const tbb::spin_mutex::scoped_lock&)
62 #else
63 AttributeArray::AttributeArray(const AttributeArray& rhs)
64 #endif
65 : mIsUniform(rhs.mIsUniform)
66 , mFlags(rhs.mFlags)
67 , mUsePagedRead(rhs.mUsePagedRead)
68 , mOutOfCore(rhs.mOutOfCore.load())
69 , mPageHandle()
70 {
71 if (mFlags & PARTIALREAD) mCompressedBytes = rhs.mCompressedBytes;
72 else if (rhs.mPageHandle) mPageHandle = rhs.mPageHandle->copy();
73 }
74
75
76 AttributeArray&
operator =(const AttributeArray & rhs)77 AttributeArray::operator=(const AttributeArray& rhs)
78 {
79 // if this AttributeArray has been partially read, zero the compressed bytes,
80 // so the page handle won't attempt to clean up invalid memory
81 if (mFlags & PARTIALREAD) mCompressedBytes = 0;
82 mIsUniform = rhs.mIsUniform;
83 mFlags = rhs.mFlags;
84 mUsePagedRead = rhs.mUsePagedRead;
85 mOutOfCore.store(rhs.mOutOfCore);
86 if (mFlags & PARTIALREAD) mCompressedBytes = rhs.mCompressedBytes;
87 else if (rhs.mPageHandle) mPageHandle = rhs.mPageHandle->copy();
88 else mPageHandle.reset();
89 return *this;
90 }
91
92
93 AttributeArray::Ptr
create(const NamePair & type,Index length,Index stride,bool constantStride,const Metadata * metadata,const ScopedRegistryLock * lock)94 AttributeArray::create(const NamePair& type, Index length, Index stride,
95 bool constantStride, const Metadata* metadata, const ScopedRegistryLock* lock)
96 {
97 auto* registry = getAttributeRegistry();
98 tbb::spin_mutex::scoped_lock _lock;
99 if (!lock) _lock.acquire(registry->mMutex);
100
101 auto iter = registry->mMap.find(type);
102 if (iter == registry->mMap.end()) {
103 OPENVDB_THROW(LookupError,
104 "Cannot create attribute of unregistered type " << type.first << "_" << type.second);
105 }
106 return (iter->second)(length, stride, constantStride, metadata);
107 }
108
109
110 bool
isRegistered(const NamePair & type,const ScopedRegistryLock * lock)111 AttributeArray::isRegistered(const NamePair& type, const ScopedRegistryLock* lock)
112 {
113 LockedAttributeRegistry* registry = getAttributeRegistry();
114 tbb::spin_mutex::scoped_lock _lock;
115 if (!lock) _lock.acquire(registry->mMutex);
116 return (registry->mMap.find(type) != registry->mMap.end());
117 }
118
119
120 void
clearRegistry(const ScopedRegistryLock * lock)121 AttributeArray::clearRegistry(const ScopedRegistryLock* lock)
122 {
123 LockedAttributeRegistry* registry = getAttributeRegistry();
124 tbb::spin_mutex::scoped_lock _lock;
125 if (!lock) _lock.acquire(registry->mMutex);
126 registry->mMap.clear();
127 }
128
129
130 void
registerType(const NamePair & type,FactoryMethod factory,const ScopedRegistryLock * lock)131 AttributeArray::registerType(const NamePair& type, FactoryMethod factory, const ScopedRegistryLock* lock)
132 {
133 { // check the type of the AttributeArray generated by the factory method
134 auto array = (*factory)(/*length=*/0, /*stride=*/0, /*constantStride=*/false, /*metadata=*/nullptr);
135 const NamePair& factoryType = array->type();
136 if (factoryType != type) {
137 OPENVDB_THROW(KeyError, "Attribute type " << type.first << "_" << type.second
138 << " does not match the type created by the factory method "
139 << factoryType.first << "_" << factoryType.second << ".");
140 }
141 }
142
143 LockedAttributeRegistry* registry = getAttributeRegistry();
144 tbb::spin_mutex::scoped_lock _lock;
145 if (!lock) _lock.acquire(registry->mMutex);
146
147 registry->mMap[type] = factory;
148 }
149
150
151 void
unregisterType(const NamePair & type,const ScopedRegistryLock * lock)152 AttributeArray::unregisterType(const NamePair& type, const ScopedRegistryLock* lock)
153 {
154 LockedAttributeRegistry* registry = getAttributeRegistry();
155 tbb::spin_mutex::scoped_lock _lock;
156 if (!lock) _lock.acquire(registry->mMutex);
157
158 registry->mMap.erase(type);
159 }
160
161
162 void
setTransient(bool state)163 AttributeArray::setTransient(bool state)
164 {
165 if (state) mFlags = static_cast<uint8_t>(mFlags | Int16(TRANSIENT));
166 else mFlags = static_cast<uint8_t>(mFlags & ~Int16(TRANSIENT));
167 }
168
169
170 void
setHidden(bool state)171 AttributeArray::setHidden(bool state)
172 {
173 if (state) mFlags = static_cast<uint8_t>(mFlags | Int16(HIDDEN));
174 else mFlags = static_cast<uint8_t>(mFlags & ~Int16(HIDDEN));
175 }
176
177
178 void
setStreaming(bool state)179 AttributeArray::setStreaming(bool state)
180 {
181 if (state) mFlags = static_cast<uint8_t>(mFlags | Int16(STREAMING));
182 else mFlags = static_cast<uint8_t>(mFlags & ~Int16(STREAMING));
183 }
184
185
186 void
setConstantStride(bool state)187 AttributeArray::setConstantStride(bool state)
188 {
189 if (state) mFlags = static_cast<uint8_t>(mFlags | Int16(CONSTANTSTRIDE));
190 else mFlags = static_cast<uint8_t>(mFlags & ~Int16(CONSTANTSTRIDE));
191 }
192
193
194 bool
operator ==(const AttributeArray & other) const195 AttributeArray::operator==(const AttributeArray& other) const
196 {
197 this->loadData();
198 other.loadData();
199
200 if (this->mUsePagedRead != other.mUsePagedRead ||
201 this->mFlags != other.mFlags) return false;
202 return this->isEqual(other);
203 }
204
205 } // namespace points
206 } // namespace OPENVDB_VERSION_NAME
207 } // namespace openvdb
208