Loading...
Searching...
No Matches
dependencyForwardingSceneIndex.h
1//
2// Copyright 2022 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_IMAGING_HD_DEPENDENCY_FORWARDING_SCENE_INDEX_H
8#define PXR_IMAGING_HD_DEPENDENCY_FORWARDING_SCENE_INDEX_H
9
11
12#include "pxr/imaging/hd/api.h"
13#include "pxr/imaging/hd/filteringSceneIndex.h"
14
15#include <tbb/concurrent_unordered_map.h>
16#include <tbb/concurrent_unordered_set.h>
17#include <tbb/concurrent_vector.h>
18
19#include <atomic>
20
21PXR_NAMESPACE_OPEN_SCOPE
22
23class HdDependencyForwardingSceneIndex;
24TF_DECLARE_REF_PTRS(HdDependencyForwardingSceneIndex);
25
26
27class HdDependencyForwardingSceneIndex
29{
30public:
31
32 static HdDependencyForwardingSceneIndexRefPtr New(
33 HdSceneIndexBaseRefPtr inputScene) {
34 return TfCreateRefPtr(
35 new HdDependencyForwardingSceneIndex(inputScene));
36 }
37
38 // satisfying HdSceneIndexBase
39 HD_API
40 HdSceneIndexPrim GetPrim(const SdfPath &primPath) const override;
41
42 HD_API
43 SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const override;
44
45 // Provided for the sake of unit testing.
46 // By default, or if SetManualGarbageCollect(false) is called,
47 // we call RemoveDeletedEntries at the end of all of the notice
48 // handlers...
49 HD_API
50 void SetManualGarbageCollect(bool manualGarbageCollect);
51
52protected:
53 HD_API
54 HdDependencyForwardingSceneIndex(HdSceneIndexBaseRefPtr inputScene);
55
56 // satisfying HdSingleInputFilteringSceneIndexBase
57 void _PrimsAdded(
58 const HdSceneIndexBase &sender,
59 const HdSceneIndexObserver::AddedPrimEntries &entries) override;
60
61 void _PrimsRemoved(
62 const HdSceneIndexBase &sender,
63 const HdSceneIndexObserver::RemovedPrimEntries &entries) override;
64
65 void _PrimsDirtied(
66 const HdSceneIndexBase &sender,
67 const HdSceneIndexObserver::DirtiedPrimEntries &entries) override;
68private:
69
70 // -----------------------------------------------------------------------
71
72 // XXX: Note for future performance improvements: giving dependency schemas
73 // the ability to represent set->set dependencies, and compacting
74 // these locator entries into set->set, could potentially be a big perf
75 // win, since set/set intersections are vastly more efficient than
76 // pairwise locator intersections.
77 //
78 // Since multiple affected prims could be populating _dependedOn locator
79 // entries from different threads, and we use the individual dependency
80 // name for lifetime management, we'd probably need to populate these
81 // individually and then compact the next time we get a chance from
82 // a single threaded API (e.g. notice handler).
83 //
84 // We can compact as follows:
85 // 1. Construct a dictionary of "affectedDataSourceLocator" ->
86 // vector of "dependedOnDataSourceLocator", and then flatten that into
87 // a locator set.
88 // 2. Construct a dictionary of "dependedOnDataSourceLocatorSet" ->
89 // vector of "affectedDataSourceLocator", and then flatten that into
90 // a locator set.
91 struct _LocatorsEntry
92 {
93 HdDataSourceLocator dependedOnDataSourceLocator;
94 HdDataSourceLocator affectedDataSourceLocator;
95 };
96
97 // The token used as a key here corresponds to the first member of an
98 // HdDependenciesSchema::EntryPair and provides an identifier for a
99 // dependency declaration. An affected prim may depend on more than one
100 // data source of another prim. That identifier is used here for updating
101 // or removing a dependency.
102 using _LocatorsEntryMap = tbb::concurrent_unordered_map<
103 TfToken,
104 _LocatorsEntry,
106
107
108 struct _AffectedPrimDependencyEntry
109 {
110 // Gotta define this stuff because the atomic_bool isn't copyable.
111 // We know we'll only be copying in single-threaded cases, so the naive
112 // implementation is fine...
113 // flaggedForDeletion is an atomic_bool so we can use parallel for in
114 // the notice handlers.
115 _AffectedPrimDependencyEntry()
116 : locatorsEntryMap(), flaggedForDeletion(false) {}
117 _AffectedPrimDependencyEntry(const _AffectedPrimDependencyEntry &rhs)
118 : locatorsEntryMap(rhs.locatorsEntryMap)
119 , flaggedForDeletion(rhs.flaggedForDeletion.load()) {}
120 _AffectedPrimDependencyEntry(_AffectedPrimDependencyEntry &&rhs)
121 : locatorsEntryMap(std::move(rhs.locatorsEntryMap))
122 , flaggedForDeletion(rhs.flaggedForDeletion.load()) {}
123 _AffectedPrimDependencyEntry& operator=(
124 const _AffectedPrimDependencyEntry& rhs) {
125 if (this != &rhs) {
126 locatorsEntryMap = rhs.locatorsEntryMap;
127 flaggedForDeletion = rhs.flaggedForDeletion.load();
128 }
129 return *this;
130 }
131
132 _LocatorsEntryMap locatorsEntryMap;
133 std::atomic_bool flaggedForDeletion;
134 };
135
136 // Reverse mapping from a depended on prim to its discovered-thus-far
137 // affected prims and data source locators..
138 using _AffectedPrimsDependencyMap = tbb::concurrent_unordered_map<
139 SdfPath,
140 _AffectedPrimDependencyEntry,
141 SdfPath::Hash>;
142
143
144 // Top-level map keyed by paths of depended-on paths
145 using _DependedOnPrimsAffectedPrimsMap = tbb::concurrent_unordered_map<
146 SdfPath,
147 _AffectedPrimsDependencyMap,
148 SdfPath::Hash>;
149
150
151 // Lazily-populated mapping of depended on paths to the affected paths
152 // and data source locators used for forwarding of dirtying.
153 // NOTE: This is mutable because it can be updated during calls to
154 // GetPrim -- which is defined as const within HdSceneIndexBase.
155 // This is in service of lazy population goals.
156 //
157 // XXX: This map is "dependedOn" -> "affected" -> vec (loc -> loc)
158 // ... a potential optimization we might want to make is to switch the
159 // organization to: "dependedOn" -> loc -> vec ("affected" -> loc).
160 // This would make dependency management more difficult; since dependencies
161 // may be introduced from different threads, we'd probably need to compact
162 // them into the latter representation. But it would introduce more
163 // early-out opportunities in PrimsDirtied, which would be great especially
164 // for prims that have a high dependency fan-out (e.g. scene globals).
165 mutable _DependedOnPrimsAffectedPrimsMap _dependedOnPrimToDependentsMap;
166
167
168 // -----------------------------------------------------------------------
169
170 using _PathSet = tbb::concurrent_unordered_set<SdfPath, SdfPath::Hash>;
171
172 struct _AffectedPrimToDependsOnPathsEntry
173 {
174 // Gotta define this stuff because the atomic_bool isn't copyable.
175 // We know we'll only be copying in single-threaded cases, so the naive
176 // implementation is fine...
177 _AffectedPrimToDependsOnPathsEntry()
178 : dependsOnPaths(), flaggedForDeletion(false) {}
179 _AffectedPrimToDependsOnPathsEntry(
180 const _AffectedPrimToDependsOnPathsEntry &rhs)
181 : dependsOnPaths(rhs.dependsOnPaths)
182 , flaggedForDeletion(rhs.flaggedForDeletion.load()) {}
183 _AffectedPrimToDependsOnPathsEntry(
184 _AffectedPrimToDependsOnPathsEntry &&rhs)
185 : dependsOnPaths(std::move(rhs.dependsOnPaths))
186 , flaggedForDeletion(rhs.flaggedForDeletion.load()) {}
187 _AffectedPrimToDependsOnPathsEntry& operator=(
188 const _AffectedPrimToDependsOnPathsEntry& rhs) {
189 if (this != &rhs) {
190 dependsOnPaths = rhs.dependsOnPaths;
191 flaggedForDeletion = rhs.flaggedForDeletion.load();
192 }
193 return *this;
194 }
195
196 _PathSet dependsOnPaths;
197 std::atomic_bool flaggedForDeletion;
198 };
199
200
201 using _AffectedPrimToDependsOnPathsEntryMap = tbb::concurrent_unordered_map<
202 SdfPath,
203 _AffectedPrimToDependsOnPathsEntry,
204 SdfPath::Hash>;
205
206 // lazily-populated set of depended on paths for affected prims. This
207 // is used to update _dependedOnPrimToDependentsMap when a prim's
208 // __dependencies data source is dirtied (or the prim is removed)
209 // NOTE: This is mutable because it can be updated during calls to
210 // GetPrim -- which is defined as const within HdSceneIndexBase.
211 // This is in service of lazy population goals.
212 mutable _AffectedPrimToDependsOnPathsEntryMap
213 _affectedPrimToDependsOnPathsMap;
214
215 // -----------------------------------------------------------------------
216
217 void _ClearDependencies(const SdfPath &primPath);
218 void _UpdateDependencies(const SdfPath &primPath) const;
219 void _UpdateDependencies(
220 const SdfPath &primPath,
221 const HdSceneIndexPrim &prim) const;
222 void _ResetDependencies();
223
224 // -----------------------------------------------------------------------
225
226 // Dependencies may reasonably describe cycles given that:
227 // 1) Dependancies can exist at different levels of data source nesting
228 // 2) Dependancy declarations can be present from multiple upstream
229 // scene indices -- each of which draws its value from its input.
230 // In that case, it's not a cycle which affects a computed value but
231 // rather indicates to observers of this scene index that a value
232 // should be repulled.
233 //
234 // When following affected paths to propogate dirtiness, we need to detect
235 // cycles to avoiding hanging. This is done is by sending a "visited" set
236 // containing these node keys:
237 struct _VisitedNode
238 {
239 SdfPath primPath;
240 HdDataSourceLocator locator;
241
242 inline bool operator==(_VisitedNode const &rhs) const noexcept
243 {
244 return primPath == rhs.primPath && locator == rhs.locator;
245 }
246
247 template <class HashState>
248 friend void TfHashAppend(HashState &h, _VisitedNode const &myObj) {
249 h.Append(myObj.primPath);
250 h.Append(myObj.locator);
251 }
252
253 inline size_t Hash() const;
254 struct HashFunctor {
255 size_t operator()(_VisitedNode const &node) const {
256 return node.Hash();
257 }
258 };
259 };
260
261 using _VisitedNodeSet = tbb::concurrent_unordered_set<
262 _VisitedNode,
263 _VisitedNode::HashFunctor>;
264
265 using _AdditionalDirtiedVector =
266 tbb::concurrent_vector<HdSceneIndexObserver::DirtiedPrimEntry>;
267
268 // impl for PrimDirtied which handles propogation of PrimDirtied notices
269 // for affected prims/dataSources.
270 void _PrimDirtied(
271 const SdfPath &primPath,
272 const HdDataSourceLocatorSet &sourceLocator,
273 _VisitedNodeSet *visited,
274 _AdditionalDirtiedVector *moreDirtiedEntries,
275 _PathSet *rebuildDependencies);
276
277 // -----------------------------------------------------------------------
278
279 // accumulated depended-on prim paths whose affected prims may have been
280 // removed.
281 mutable _PathSet _potentiallyDeletedDependedOnPaths;
282
283 // Accumulated affected prim paths who may have been deleted. Normally this
284 // is needed to track affected prims which have an entry in
285 // _dependedOnPrimToDependentsMap but which is empty -- and therefore
286 // won't be handled by their dependencies inclusion in
287 // _potentiallyDeletedDependedOnPaths
288 mutable _PathSet _potentiallyDeletedAffectedPaths;
289
290 // -----------------------------------------------------------------------
291
292public:
293 // XXX does thread-unsafe deletion.
294 // NOTE: optional arguments are in service of unit testing to provide
295 // insight in to what was removed.
296 HD_API
297 void RemoveDeletedEntries(
298 SdfPathVector *removedAffectedPrimPaths = nullptr,
299 SdfPathVector *removedDependedOnPrimPaths = nullptr);
300
301private:
302 bool _manualGarbageCollect;
303};
304
305
306inline size_t
307HdDependencyForwardingSceneIndex::_VisitedNode::Hash() const
308{
309 return TfHash()(*this);
310}
311
312PXR_NAMESPACE_CLOSE_SCOPE
313
314#endif
Represents an object that can identify the location of a data source.
Represents a set of data source locators closed under descendancy.
Abstract interface to scene data.
Definition: sceneIndex.h:54
virtual SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const =0
Returns the paths of all scene index prims located immediately below primPath.
virtual HdSceneIndexPrim GetPrim(const SdfPath &primPath) const =0
Returns a pair of (prim type, datasource).
An abstract base class for a filtering scene index that observes a single input scene index.
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:281
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:472
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
#define TF_DECLARE_REF_PTRS(type)
Define standard ref pointer types.
Definition: declarePtrs.h:58
STL namespace.
Small struct representing a 'prim' in the Hydra scene index.
Definition: sceneIndex.h:35
Functor to use for hash maps from tokens to other things.
Definition: token.h:149