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 _ResetDependencies();
220
221 // -----------------------------------------------------------------------
222
223 // Dependencies may reasonably describe cycles given that:
224 // 1) Dependancies can exist at different levels of data source nesting
225 // 2) Dependancy declarations can be present from multiple upstream
226 // scene indices -- each of which draws its value from its input.
227 // In that case, it's not a cycle which affects a computed value but
228 // rather indicates to observers of this scene index that a value
229 // should be repulled.
230 //
231 // When following affected paths to propogate dirtiness, we need to detect
232 // cycles to avoiding hanging. This is done is by sending a "visited" set
233 // containing these node keys:
234 struct _VisitedNode
235 {
236 SdfPath primPath;
237 HdDataSourceLocator locator;
238
239 inline bool operator==(_VisitedNode const &rhs) const noexcept
240 {
241 return primPath == rhs.primPath && locator == rhs.locator;
242 }
243
244 template <class HashState>
245 friend void TfHashAppend(HashState &h, _VisitedNode const &myObj) {
246 h.Append(myObj.primPath);
247 h.Append(myObj.locator);
248 }
249
250 inline size_t Hash() const;
251 struct HashFunctor {
252 size_t operator()(_VisitedNode const &node) const {
253 return node.Hash();
254 }
255 };
256 };
257
258 using _VisitedNodeSet = tbb::concurrent_unordered_set<
259 _VisitedNode,
260 _VisitedNode::HashFunctor>;
261
262 using _AdditionalDirtiedVector =
263 tbb::concurrent_vector<HdSceneIndexObserver::DirtiedPrimEntry>;
264
265 // impl for PrimDirtied which handles propogation of PrimDirtied notices
266 // for affected prims/dataSources.
267 void _PrimDirtied(
268 const SdfPath &primPath,
269 const HdDataSourceLocatorSet &sourceLocator,
270 _VisitedNodeSet *visited,
271 _AdditionalDirtiedVector *moreDirtiedEntries,
272 _PathSet *rebuildDependencies);
273
274 // -----------------------------------------------------------------------
275
276 // accumulated depended-on prim paths whose affected prims may have been
277 // removed.
278 mutable _PathSet _potentiallyDeletedDependedOnPaths;
279
280 // Accumulated affected prim paths who may have been deleted. Normally this
281 // is needed to track affected prims which have an entry in
282 // _dependedOnPrimToDependentsMap but which is empty -- and therefore
283 // won't be handled by their dependencies inclusion in
284 // _potentiallyDeletedDependedOnPaths
285 mutable _PathSet _potentiallyDeletedAffectedPaths;
286
287 // -----------------------------------------------------------------------
288
289public:
290 // XXX does thread-unsafe deletion.
291 // NOTE: optional arguments are in service of unit testing to provide
292 // insight in to what was removed.
293 HD_API
294 void RemoveDeletedEntries(
295 SdfPathVector *removedAffectedPrimPaths = nullptr,
296 SdfPathVector *removedDependedOnPrimPaths = nullptr);
297
298private:
299 bool _manualGarbageCollect;
300};
301
302
303inline size_t
304HdDependencyForwardingSceneIndex::_VisitedNode::Hash() const
305{
306 return TfHash()(*this);
307}
308
309PXR_NAMESPACE_CLOSE_SCOPE
310
311#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:274
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