HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
locatorCachingSceneIndex.h
Go to the documentation of this file.
1 //
2 // Copyright 2026 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_HDSI_LOCATOR_CACHING_SCENE_INDEX
8 #define PXR_IMAGING_HDSI_LOCATOR_CACHING_SCENE_INDEX
9 
10 #include "pxr/imaging/hd/api.h"
12 #include "pxr/usd/sdf/pathTable.h"
14 #include <mutex>
15 
17 
19 
20 ///
21 /// \class HdsiLocatorCachingSceneIndex
22 ///
23 /// A scene index that caches data sources for specified locators
24 /// on specified prim types. This avoids redundant computation
25 /// when scene indexes query the same locator on the same prims
26 /// multiple times.
27 ///
28 /// \section cachingStrategies Caching Scenarios in Hydra Scene Indexes
29 ///
30 /// The basic purpose of Hydra scene indexes is to transmit
31 /// scene information to a renderer. In the simplest idealized
32 /// form this can be thought of as a for() loop over the scene
33 /// contents. In this single-traversal scenario, there is no need
34 /// for scene indexes to internally cache data that would be visisted
35 /// only once. In practice, however, several situations motivate
36 /// some degree of caching.
37 ///
38 /// The first is when scene indexes access data in other prims.
39 /// A common example is resolving material bindings, which reads
40 /// information from the material bound to each geometry prim.
41 /// If the same material is bound to multiple prims it will be read
42 /// multiple times. This pattern occurs in any binding-like concept.
43 ///
44 /// Another inter-prim dependency situation is flattening. Hydra scene
45 /// indexes present flat data to the renderer, without further implied
46 /// hierarchical transformation of data. Since many input scene
47 /// descriptions heavily rely on hierarchical structure of data,
48 /// such as for xforms, a flattening scene index is used. In this
49 /// situation, sibling prims access a shared parent multiple times.
50 ///
51 /// A third case is repeated access to the same data source by
52 /// distinct scene indexes in sequence. For example, there might
53 /// be a series of scene indexes that analyze and modify a material
54 /// network. In such cases, it may be preferable to cache intermediate
55 /// state(s) of the material network to avoid re-running a growing
56 /// series of transformations as downstream scene indexes each
57 /// traverse the incoming material network.
58 ///
59 /// A fourth case is interactive use when locator-based invalidation
60 /// granularity is insufficient to avoid repeated computation.
61 /// For example, some consumers of a scene index may not be
62 /// able to retain full granularity of individual primvar updates,
63 /// and instead collapse all primvar invalidation into a single
64 /// "dirty bit". Observers of the dirty bit will have no choice
65 /// but to re-query all primvars, widening the computation.
66 /// Caching can avoid incurring undue extra cost.
67 ///
68 /// In each of these situations, the appropriate scope of cache
69 /// is distinct. This is why Hydra does not provide built-in
70 /// "one size fits all" caching and instead encourages specific
71 /// approaches based on the need.
72 ///
73 ///
74 /// \section cachingSceneIndex Cache Implementation with HdsiLocatorCachingSceneIndex
75 ///
76 /// HdsiLocatorCachingSceneIndex provides a response to these needs.
77 /// It is a configurable, targeted cache to support specific cases
78 /// where memoizing multiple-access to the same data is appropriate.
79 ///
80 /// Scene index plugins should insert HdsiLocatorCachingSceneIndex instances,
81 /// configured appropriately, based on the known structure of their
82 /// computations: either caching input dependencies or their outputs.
83 ///
84 /// For computations that pull on upstream prims from scene-defined paths,
85 /// such as material bindings, it may be appropriate to insert a caching
86 /// index immedately before the resolving scene index, configured
87 /// according to the prim types and locators it depends upon.
88 ///
89 /// In other cases it may be appropriate to append a caching index
90 /// directly after the scene index producing an expensive result,
91 /// if that result is expected to be accessed broadly or repeatedly.
92 ///
93 /// Flattening is a special case where the scene index wants to
94 /// compute a value on a prim, cache it, and then re-use that in
95 /// comptutations on child prims. HdFlatteningSceneIndex, rather than
96 /// HdsiLocatorCachingSceneIndex, is appropriate for such cases.
97 ///
98 ///
99 /// \section cacheInvalidation Cache Invalidation
100 ///
101 /// HdsiLocatorCachingSceneIndex relies on PrimsDirtied
102 /// notification to invalidate internal cache state correctly.
103 ///
104 /// There are two approaches to dependency invalidation in Hydra.
105 ///
106 /// The first is that a scene index may directly propagate
107 /// invalidation to dependent prims and locators inside its
108 /// PrimsDirtied notification handler.
109 ///
110 /// The second is that a scene index can overlay the
111 /// HdDependencySchema, and express its dependencies in
112 /// that form. This approach relies on a downsteam
113 /// HdDependencyForwardingSceneIndex to observe those dependnecies,
114 /// and propagate invalidation to dependent prims and locators
115 /// based on the provided dependency data.
116 ///
117 /// Since HdsiLocatorCachingSceneIndex has no way of knowing
118 /// what approach is used by upstream scene indexes, a
119 /// straightforward way to achieve correct cache invalidation is
120 /// by inserting a HdDependencyForwardingSceneIndex directly before
121 /// the HdsiLocatorCachingSceneIndex in the scene index chain.
122 /// The method AddDependencyForwardingAndLocatorCache() does this.
123 ///
124 /// Note that this does rely on upstream scene indexes properly
125 /// implementing one or the other of the two approaches above.
126 ///
127 ///
128 /// \section internalState Internal Runtime State Caching
129 ///
130 /// The discussion above pertains to caching the scene index data
131 /// produced by a scene index and seen by observers. Some scene
132 /// index implementations contain internal runtime state (as C++
133 /// member variables or thread-safe/protected global state).
134 ///
135 /// Maintaining integrity of internal runtime cache state is the
136 /// responsibility of the scene index, and this will require handling
137 /// inside change notification methods. Such state is not addressed
138 /// by the dependency schema or HdDependencyForwardingSceneIndex.
139 ///
141 {
142 public:
143  /// Creates a new HdDependencyForwardingSceneIndex followed by a
144  /// HdsiLocatorCachingSceneIndex.
145  ///
146  /// \see New() for parameter documentation
147  HD_API
148  static HdSceneIndexBaseRefPtr
150  HdSceneIndexBaseRefPtr const& inputScene,
151  HdDataSourceLocator const& locatorToCache,
152  TfToken const& primTypeToCache);
153 
154  /// Creates a new HdsiLocatorCachingSceneIndex.
155  ///
156  /// \note AddDependencyForwardingAndLocatorCache() is recommended
157  /// for most uses. See class notes regarding cache invalidation.
158  ///
159  /// \param inputScene The upstream input scene index to cache
160  /// \param locatorToCache The data source locator to cache;
161  /// for example, HdMaterialSchema::GetDefaultLocator().
162  /// Must not be empty.
163  /// \param primTypeToCache If specified, caching only applies
164  /// to prims of this data type; if empty token, caching applies
165  /// to all prim types
166  HD_API
167  static HdsiLocatorCachingSceneIndexRefPtr
168  New(HdSceneIndexBaseRefPtr const& inputScene,
169  HdDataSourceLocator const& locatorToCache,
170  TfToken const& primTypeToCache);
171 
172  HD_API
174 
175  HD_API
176  HdSceneIndexPrim GetPrim(const SdfPath &primPath) const override;
177 
178  HD_API
179  SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const override;
180 
181 protected:
182  HD_API
184  HdSceneIndexBaseRefPtr const& inputScene,
185  HdDataSourceLocator const& locatorToCache,
186  TfToken const& primTypeToCache);
187 
188  void _PrimsAdded(
189  const HdSceneIndexBase &sender,
190  const HdSceneIndexObserver::AddedPrimEntries &entries) override;
191  void _PrimsRemoved(
192  const HdSceneIndexBase &sender,
193  const HdSceneIndexObserver::RemovedPrimEntries &entries) override;
194  void _PrimsDirtied(
195  const HdSceneIndexBase &sender,
196  const HdSceneIndexObserver::DirtiedPrimEntries &entries) override;
197 
198  // A data source that delegates back to HdsiLocatorCachingSceneIndex, allowing
199  // it to manage invalidation.
201  {
202  public:
204 
205  TfTokenVector GetNames() override;
206  HdDataSourceBaseHandle Get(const TfToken &name) override;
207 
208  private:
209  _DataSource(
210  HdsiLocatorCachingSceneIndex const* cachingSceneIndex,
211  SdfPath const& primPath,
212  HdDataSourceLocator const& locator,
213  HdContainerDataSourceHandle const& inputDataSource);
214 
215  const HdsiLocatorCachingSceneIndex& _cachingSceneIndex;
216  const SdfPath _primPath;
217  const HdDataSourceLocator _locator;
218  const HdContainerDataSourceHandle _inputDataSource;
219  };
220 
221  // Retrieve data for the requested locator, populating and
222  // re-using cached data sources as appropriate.
223  HdDataSourceBaseHandle
225  SdfPath const& primPath,
226  HdDataSourceLocator const& locator,
227  HdContainerDataSourceHandle const& inputDataSource) const;
228 
229 private: // data
230 
231  // Cache of data sources within a prim, by locator
232  using _LocatorDataSourceMap =
234 
235  // Cache of data sources, by prim
237 
238  // Cache strategy parameters.
239  const HdDataSourceLocator _locatorToCache;
240  const TfToken _primTypeToCache;
241 
242  // Cache contents.
243  mutable _PrimCache _primDsCache;
244  mutable std::mutex _cacheMutex;
245 };
246 
248 
249 #endif
void _PrimsDirtied(const HdSceneIndexBase &sender, const HdSceneIndexObserver::DirtiedPrimEntries &entries) override
void _PrimsRemoved(const HdSceneIndexBase &sender, const HdSceneIndexObserver::RemovedPrimEntries &entries) override
HD_API SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const override
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
#define HD_API
Definition: api.h:23
HD_API HdsiLocatorCachingSceneIndex(HdSceneIndexBaseRefPtr const &inputScene, HdDataSourceLocator const &locatorToCache, TfToken const &primTypeToCache)
void _PrimsAdded(const HdSceneIndexBase &sender, const HdSceneIndexObserver::AddedPrimEntries &entries) override
Definition: token.h:70
static HD_API HdsiLocatorCachingSceneIndexRefPtr New(HdSceneIndexBaseRefPtr const &inputScene, HdDataSourceLocator const &locatorToCache, TfToken const &primTypeToCache)
std::vector< class SdfPath > SdfPathVector
HdDataSourceBaseHandle _GetWithCache(SdfPath const &primPath, HdDataSourceLocator const &locator, HdContainerDataSourceHandle const &inputDataSource) const
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:440
GLuint const GLchar * name
Definition: glcorearb.h:786
Definition: path.h:280
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
HD_API ~HdsiLocatorCachingSceneIndex() override
HdDataSourceBaseHandle Get(const TfToken &name) override
static HD_API HdSceneIndexBaseRefPtr AddDependencyForwardingAndCache(HdSceneIndexBaseRefPtr const &inputScene, HdDataSourceLocator const &locatorToCache, TfToken const &primTypeToCache)
HD_API HdSceneIndexPrim GetPrim(const SdfPath &primPath) const override
PXR_NAMESPACE_OPEN_SCOPE TF_DECLARE_REF_PTRS(HdsiLocatorCachingSceneIndex)