Loading...
Searching...
No Matches
vectorImpl_Shared.h
1//
2// Copyright 2025 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_EXEC_VDF_VECTOR_IMPL_SHARED_H
8#define PXR_EXEC_VDF_VECTOR_IMPL_SHARED_H
9
10#include "pxr/pxr.h"
11
12#include "pxr/exec/vdf/api.h"
13#include "pxr/exec/vdf/vectorData.h"
14
15#include "pxr/base/tf/delegatedCountPtr.h"
16#include "pxr/base/vt/array.h"
17
18#include <atomic>
19
20PXR_NAMESPACE_OPEN_SCOPE
21
27class VDF_API_TYPE Vdf_VectorImplShared final
28 : public Vdf_VectorData
29{
30public:
31 // This class only stores a TfDelegatedCountPtr to _SharedSource, so most
32 // of the constructor, destructor, and operator heavy lifting is
33 // implemented in the equivalent methods on TfDelegatedCountPtr.
34 //
35 VDF_API
36 explicit Vdf_VectorImplShared(DataHolder* srcData);
37 VDF_API
39 VDF_API
41 VDF_API
42 ~Vdf_VectorImplShared() override;
43
44 // Returns the type_info for the held data.
45 //
46 VDF_API
47 const std::type_info& GetTypeInfo() const override;
48
49 // Sets \p destData to an empty data of this data's held type.
50 //
51 VDF_API
52 void NewEmpty(size_t size, DataHolder* destData) const override;
53
54 // Sets \p destData to a single element of this data's held type.
55 //
56 VDF_API
57 void NewSingle(DataHolder* destData) const override;
58
59 // Sets \p destData to a sparse vector of this data's held type.
60 //
61 VDF_API
62 void NewSparse(size_t size, size_t first, size_t last,
63 DataHolder* destData) const override;
64
65 // Sets \p destData to a dense vector of this data's held type.
66 //
67 VDF_API
68 void NewDense(size_t size, DataHolder* destData) const override;
69
70 // Moves this vector's held data into the \p destData.
71 //
72 VDF_API
73 void MoveInto(Vdf_VectorData::DataHolder* destData) override;
74
75 // Clones this vector's data object into \p destData. Causes the _refCount
76 // to increase.
77 //
78 VDF_API
79 void Clone(Vdf_VectorData::DataHolder* destData) const override;
80
81 // This is like the clone method, only it uses a mask to potentially
82 // copy a smaller set of this vector into \p destData. This does not
83 // cause the _refCount to increase.
84 //
85 VDF_API
86 void CloneSubset(const VdfMask& mask,
87 Vdf_VectorData::DataHolder* destData) const override;
88
89 // Boxes the stored data. As a result of this, \p destData will store a
90 // single element, which is a Vdf_BoxedContainer containing all the
91 // elements stored in this vector data instance.
92 //
93 // Only the data elements specified in \p bits will be pushed into the
94 // boxed container.
95 //
96 VDF_API
97 void Box(const VdfMask::Bits& bits,
98 Vdf_VectorData::DataHolder* destData) const override;
99
100 // Merges the held data into \p destData.
101 //
102 VDF_API
103 void Merge(const VdfMask::Bits& bits,
104 Vdf_VectorData::DataHolder* destData) const override;
105
106 // Expand the storage capabilities of the underlying vector
107 // implementation, if necessary.
108 //
109 // Note, this should never get called on VectorImpl_Shared as it mutates
110 // the held data.
111 //
112 VDF_API
113 void Expand(size_t first, size_t last) override;
114
115 // Returns the size of the vector. Note that there may not be storage
116 // allocated for all the elements in the vector size.
117 //
118 VDF_API
119 size_t GetSize() const override;
120
121 // Returns the number of elements stored in the vector implementation.
122 //
123 VDF_API
124 size_t GetNumStoredElements() const override;
125
126 // Returns a pointer to the SharedSource data structure for copyless
127 // value extraction.
128 //
129 VDF_API
130 Vt_ArrayForeignDataSource* GetSharedSource() const override;
131
132 // Returns the vector implementation details.
133 //
134 VDF_API
135 Info GetInfo() override;
136
137 // Returns the estimated size of the allocated memory for a single
138 // element stored in this vector.
139 //
140 VDF_API
141 size_t EstimateElementMemory() const override;
142
143 // Detaches \p data from its shared source data.
144 //
145 // It is the caller's responsibility to ensure that \p *data is holding a
146 // Vdf_VectorImplShared.
147 //
148 // If the ref count of the shared data is one then it is not safe to
149 // make copies of the shared source and detach at the same time. This
150 // is not an issue in practice because the executor data manager will
151 // always hold onto the last instance of the shared source. Meaning that
152 // if the ref count is one then either no clients are holding onto a copy
153 // or there is no more data manager (meaning that the vector cannot be
154 // written to). Also it is generally not thread-safe to try to make
155 // copies of something being written to concurrently so you would already
156 // have to be in a bad place for this to occur.
157 //
158 // An alternate approach would be to not optimize the refcount equals one
159 // case inside this method. Instead copies would always occur during
160 // detachment and the data manager could "unshare" previously shared
161 // vectors when they are reused. The performance benefits would be similar.
162 //
163 VDF_API
164 static void Detach(Vdf_VectorData::DataHolder* data);
165
166private:
167 // Implement a foreign data source for VtArray, it shares in the
168 // lifetime of the held DataHolder.
169 class _SharedSource: public Vt_ArrayForeignDataSource
170 {
171 public:
172 explicit _SharedSource(DataHolder* srcData);
173
174 ~_SharedSource();
175
176 // Return the held DataHolder for use in detachment.
177 Vdf_VectorData::DataHolder* GetHolder() {
178 return &_data;
179 }
180
181 // Returns true if there is only one last outstanding reference to the
182 // shared data.
183 bool IsUnique() const {
184 return _refCount.load(std::memory_order_acquire) == 1;
185 }
186
187 // Specialized TfDelegatedCountPtr operations for _SharedSource.
188 friend inline void
189 TfDelegatedCountIncrement(_SharedSource* s) noexcept {
190 s->_refCount.fetch_add(1, std::memory_order_relaxed);
191 }
192
193 friend inline void
194 TfDelegatedCountDecrement(_SharedSource* s) noexcept {
195 if (s->_refCount.fetch_sub(1, std::memory_order_release) == 1) {
196 std::atomic_thread_fence(std::memory_order_acquire);
197 delete s;
198 }
199 }
200
201 private:
202 // Callback for VtArray foreign data source.
203 static void _Detached(Vt_ArrayForeignDataSource* selfBase);
204
206 };
207
209};
210
211PXR_NAMESPACE_CLOSE_SCOPE
212
213#endif
Fast, compressed bit array which is capable of performing logical operations without first decompress...
Stores a pointer to a ValueType which uses TfDelegatedCountIncrement and TfDelegatedCountDecrement to...
Abstract base class for storing data in a VdfVector.
Definition: vectorData.h:27
Implements a Vdf_VectorData storage the supports reference counted sharing of other vector implementa...
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:37