dependencyForwardingSceneIndex.h
1 //
2 // Copyright 2022 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_IMAGING_HD_DEPENDENCY_FORWARDING_SCENE_INDEX_H
25 #define PXR_IMAGING_HD_DEPENDENCY_FORWARDING_SCENE_INDEX_H
26 
28 
29 #include "pxr/imaging/hd/api.h"
30 #include "pxr/imaging/hd/filteringSceneIndex.h"
31 
32 #include <tbb/concurrent_unordered_map.h>
33 #include <tbb/concurrent_unordered_set.h>
34 
35 PXR_NAMESPACE_OPEN_SCOPE
36 
37 class HdDependencyForwardingSceneIndex;
38 TF_DECLARE_REF_PTRS(HdDependencyForwardingSceneIndex);
39 
40 
41 class HdDependencyForwardingSceneIndex
43 {
44 public:
45 
46  static HdDependencyForwardingSceneIndexRefPtr New(
47  HdSceneIndexBaseRefPtr inputScene) {
48  return TfCreateRefPtr(
49  new HdDependencyForwardingSceneIndex(inputScene));
50  }
51 
52  // satisfying HdSceneIndexBase
53  HdSceneIndexPrim GetPrim(const SdfPath &primPath) const override;
54  SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const override;
55 
56 
57 protected:
58  HD_API
59  HdDependencyForwardingSceneIndex(HdSceneIndexBaseRefPtr inputScene);
60 
61  // satisfying HdSingleInputFilteringSceneIndexBase
62  void _PrimsAdded(
63  const HdSceneIndexBase &sender,
64  const HdSceneIndexObserver::AddedPrimEntries &entries) override;
65 
66  void _PrimsRemoved(
67  const HdSceneIndexBase &sender,
68  const HdSceneIndexObserver::RemovedPrimEntries &entries) override;
69 
70  void _PrimsDirtied(
71  const HdSceneIndexBase &sender,
72  const HdSceneIndexObserver::DirtiedPrimEntries &entries) override;
73 private:
74 
75  // -----------------------------------------------------------------------
76 
77  struct _LocatorsEntry
78  {
79  HdDataSourceLocator dependedOnDataSourceLocator;
80  HdDataSourceLocator affectedDataSourceLocator;
81  };
82 
83  // The token used as a key here corresponds to the first member of an
84  // HdDependenciesSchema::EntryPair and provides an identifier for a
85  // dependency declaration. An affected prim may depend on more than one
86  // data source of another prim. That identifier is used here for updating
87  // or removing a dependency.
88  using _LocatorsEntryMap = tbb::concurrent_unordered_map<
89  TfToken,
90  _LocatorsEntry,
92 
93 
94  struct _AffectedPrimDependencyEntry
95  {
96  _LocatorsEntryMap locatorsEntryMap;
97  bool flaggedForDeletion = false;
98  };
99 
100  // Reverse mapping from a depended on prim to its discovered-thus-far
101  // affected prims and data source locators..
102  using _AffectedPrimsDependencyMap = tbb::concurrent_unordered_map<
103  SdfPath,
104  _AffectedPrimDependencyEntry,
105  SdfPath::Hash>;
106 
107 
108  // Top-level map keyed by paths of depended-on paths
109  using _DependedOnPrimsAffectedPrimsMap = tbb::concurrent_unordered_map<
110  SdfPath,
111  _AffectedPrimsDependencyMap,
112  SdfPath::Hash>;
113 
114 
115  // Lazily-populated mapping of depended on paths to the affected paths
116  // and data source locators used for forwarding of dirtying.
117  // NOTE: This is mutable because it can be updated during calls to
118  // GetPrim -- which is defined as const within HdSceneIndexBase.
119  // This is in service of lazy population goals.
120  mutable _DependedOnPrimsAffectedPrimsMap _dependedOnPrimToDependentsMap;
121 
122 
123  // -----------------------------------------------------------------------
124 
125  using _PathSet = tbb::concurrent_unordered_set<SdfPath, SdfPath::Hash>;
126 
127  //using _DensePathSet = TfDenseHashSet<SdfPath, SdfPath::Hash>;
128 
129  struct _AffectedPrimToDependsOnPathsEntry
130  {
131  _PathSet dependsOnPaths;
132  bool flaggedForDeletion = false;
133  };
134 
135 
136  using _AffectedPrimToDependsOnPathsEntryMap = tbb::concurrent_unordered_map<
137  SdfPath,
138  _AffectedPrimToDependsOnPathsEntry,
139  SdfPath::Hash>;
140 
141  // lazily-populated set of depended on paths for affected prims. This
142  // is used to update _dependedOnPrimToDependentsMap when a prim's
143  // __dependencies data source is dirtied (or the prim is removed)
144  // NOTE: This is mutable because it can be updated during calls to
145  // GetPrim -- which is defined as const within HdSceneIndexBase.
146  // This is in service of lazy population goals.
147  mutable _AffectedPrimToDependsOnPathsEntryMap
148  _affectedPrimToDependsOnPathsMap;
149 
150  // -----------------------------------------------------------------------
151 
152  void _ClearDependencies(const SdfPath &primPath);
153  void _UpdateDependencies(const SdfPath &primPath) const;
154 
155  // -----------------------------------------------------------------------
156 
157  // Dependencies may reasonably describe cycles given that:
158  // 1) Dependancies can exist at different levels of data source nesting
159  // 2) Dependancy declarations can be present from multiple upstream
160  // scene indices -- each of which draws its value from its input.
161  // In that case, it's not a cycle which affects a computed value but
162  // rather indicates to observers of this scene index that a value
163  // should be repulled.
164  //
165  // When following affected paths to propogate dirtiness, we need to detect
166  // cycles to avoiding hanging. This is done is by sending a "visited" set
167  // containing these node keys:
168  struct _VisitedNode
169  {
170  SdfPath primPath;
171  HdDataSourceLocator locator;
172 
173  inline bool operator==(_VisitedNode const &rhs) const noexcept
174  {
175  return primPath == rhs.primPath && locator == rhs.locator;
176  }
177 
178  template <class HashState>
179  friend void TfHashAppend(HashState &h, _VisitedNode const &myObj) {
180  h.Append(myObj.primPath);
181  h.Append(myObj.locator);
182  }
183 
184  inline size_t Hash() const;
185  struct HashFunctor {
186  size_t operator()(_VisitedNode const &node) const {
187  return node.Hash();
188  }
189  };
190  };
191 
192  using _VisitedNodeSet = TfDenseHashSet<
193  _VisitedNode,
194  _VisitedNode::HashFunctor>;
195 
196  // impl for PrimDirtied which handles propogation of PrimDirtied notices
197  // for affected prims/dataSources.
198  void _PrimDirtied(
199  const SdfPath &primPath,
200  const HdDataSourceLocator &sourceLocator,
201  _VisitedNodeSet *visited,
202  HdSceneIndexObserver::DirtiedPrimEntries *moreDirtiedEntries);
203 
204  // -----------------------------------------------------------------------
205 
206  // accumulated depended-on prim paths whose affected prims may have been
207  // removed.
208  mutable _PathSet _potentiallyDeletedDependedOnPaths;
209 
210  // Accumulated affected prim paths who may have been deleted. Normally this
211  // is needed to track affected prims which have an entry in
212  // _dependedOnPrimToDependentsMap but which is empty -- and therefore
213  // won't be handled by their dependencies inclusion in
214  // _potentiallyDeletedDependedOnPaths
215  mutable _PathSet _potentiallyDeletedAffectedPaths;
216 
217  // -----------------------------------------------------------------------
218 
219 public:
220  // XXX does thread-unsafe deletion.
221  // NOTE FOR REVIEWERS: temporarily hiding this explosive public method
222  // down here while we discuss it. It's public because
223  // only the application knows when it's safe to call?
224  //
225  // NOTE: optional arguments are in service of unit testing to provide
226  // insight in to what was removed.
227  HD_API
228  void RemoveDeletedEntries(
229  SdfPathVector *removedAffectedPrimPaths = nullptr,
230  SdfPathVector *removedDependedOnPrimPaths = nullptr);
231 
232 };
233 
234 
235 inline size_t
236 HdDependencyForwardingSceneIndex::_VisitedNode::Hash() const
237 {
238  return TfHash()(*this);
239 }
240 
241 PXR_NAMESPACE_CLOSE_SCOPE
242 
243 #endif
An abstract base class for a filtering scene index that observes a single input scene index.
virtual HdSceneIndexPrim GetPrim(const SdfPath &primPath) const =0
Returns a pair of (prim type, datasource) for the object at primPath.
Functor to use for hash maps from tokens to other things.
Definition: token.h:166
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:447
Small struct representing a 'prim' in the Hydra scene index.
Definition: sceneIndex.h:49
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:87
virtual SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const =0
Returns the paths of all scene index prims located immediately below primPath.
Represents an object that can identify the location of a data source.
Abstract interface to scene data.
Definition: sceneIndex.h:62
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:290
#define TF_DECLARE_REF_PTRS(type)
Define standard ref pointer types.
Definition: declarePtrs.h:75
This is a space efficient container that mimics the TfHashSet API that uses a vector for storage when...
Definition: denseHashSet.h:58
VT_API bool operator==(VtDictionary const &, VtDictionary const &)
Equality comparison.