1 //
2 // Copyright 2016 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_USD_PCP_PRIM_INDEX_H
25 #define PXR_USD_PCP_PRIM_INDEX_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/pcp/api.h"
29 #include "pxr/usd/pcp/composeSite.h"
30 #include "pxr/usd/pcp/dynamicFileFormatDependencyData.h"
31 #include "pxr/usd/pcp/errors.h"
32 #include "pxr/usd/pcp/iterator.h"
33 #include "pxr/usd/pcp/node.h"
34 #include "pxr/usd/pcp/types.h"
35 #include "pxr/usd/sdf/declareHandles.h"
36 #include "pxr/usd/sdf/site.h"
37 #include "pxr/base/tf/declarePtrs.h"
38 #include "pxr/base/tf/hashmap.h"
39 #include "pxr/base/tf/hashset.h"
40 
41 #include <tbb/spin_rw_mutex.h>
42 
43 #include <functional>
44 #include <map>
45 #include <memory>
46 #include <unordered_set>
47 
48 PXR_NAMESPACE_OPEN_SCOPE
49 
50 SDF_DECLARE_HANDLES(SdfLayer);
51 SDF_DECLARE_HANDLES(SdfPrimSpec);
52 
53 TF_DECLARE_REF_PTRS(PcpLayerStack);
54 TF_DECLARE_WEAK_AND_REF_PTRS(PcpPrimIndex_Graph);
55 
56 class ArResolver;
57 class PcpCache;
58 class PcpPrimIndex;
59 class PcpPrimIndexInputs;
60 class PcpPrimIndexOutputs;
61 class SdfPath;
62 
63 /// \class PcpPrimIndex
64 ///
65 /// PcpPrimIndex is an index of the all sites of scene description that
66 /// contribute opinions to a specific prim, under composition
67 /// semantics.
68 ///
69 /// PcpComputePrimIndex() builds an index ("indexes") the given prim site.
70 /// At any site there may be scene description values expressing arcs
71 /// that represent instructions to pull in further scene description.
72 /// PcpComputePrimIndex() recursively follows these arcs, building and
73 /// ordering the results.
74 ///
75 class PcpPrimIndex
76 {
77 public:
78     /// Default construct an empty, invalid prim index.
79     PCP_API
80     PcpPrimIndex();
81 
82     /// Copy-construct a prim index.
83     PCP_API
84     PcpPrimIndex(const PcpPrimIndex& rhs);
85 
86     /// Assignment.
87     PcpPrimIndex &operator=(const PcpPrimIndex &rhs) {
88         PcpPrimIndex(rhs).Swap(*this);
89         return *this;
90     }
91 
92     /// Swap the contents of this prim index with \p index.
93     PCP_API
94     void Swap(PcpPrimIndex& rhs);
95 
96     /// Same as Swap(), but standard name.
swap(PcpPrimIndex & rhs)97     inline void swap(PcpPrimIndex &rhs) { Swap(rhs); }
98 
99     /// Return true if this index is valid.
100     /// A default-constructed index is invalid.
IsValid()101     bool IsValid() const { return bool(_graph); }
102 
103     PCP_API
104     void SetGraph(const PcpPrimIndex_GraphRefPtr& graph);
105     PCP_API
106     PcpPrimIndex_GraphPtr GetGraph() const;
107 
108     /// Returns the root node of the prim index graph.
109     PCP_API
110     PcpNodeRef GetRootNode() const;
111 
112     /// Returns the path of the prim whose opinions are represented by this
113     /// prim index.
114     PCP_API
115     const SdfPath& GetPath() const;
116 
117     /// Returns true if this prim index contains any scene description
118     /// opinions.
119     PCP_API
120     bool HasSpecs() const;
121 
122     /// Returns true if the prim has any authored payload arcs.
123     /// The payload contents are only resolved and included
124     /// if this prim's path is in the payload inclusion set
125     /// provided in PcpPrimIndexInputs.
126     PCP_API
127     bool HasAnyPayloads() const;
128 
129     /// Returns true if this prim index was composed in USD mode.
130     /// \see PcpCache::IsUsd().
131     PCP_API
132     bool IsUsd() const;
133 
134     /// Returns true if this prim index is instanceable.
135     /// Instanceable prim indexes with the same instance key are
136     /// guaranteed to have the same set of opinions, but may not have
137     /// local opinions about name children.
138     /// \see PcpInstanceKey
139     PCP_API
140     bool IsInstanceable() const;
141 
142     /// \name Iteration
143     /// @{
144 
145     /// Returns range of iterators that encompass all children of the root node
146     /// with the given arc type as well as their descendants, in
147     /// strong-to-weak order.
148     ///
149     /// By default, this returns a range encompassing the entire index.
150     PCP_API
151     PcpNodeRange GetNodeRange(PcpRangeType rangeType = PcpRangeTypeAll) const;
152 
153     /// Returns range of iterators that encompasses all prims, in
154     /// strong-to-weak order.
155     PCP_API
156     PcpPrimRange GetPrimRange(PcpRangeType rangeType = PcpRangeTypeAll) const;
157 
158     /// Returns range of iterators that encompasses all prims from the
159     /// site of \p node. \p node must belong to this prim index.
160     PCP_API
161     PcpPrimRange GetPrimRangeForNode(const PcpNodeRef& node) const;
162 
163     /// @}
164 
165     /// \name Lookup
166     /// @{
167 
168     /// Returns the node that brings opinions from \p primSpec into
169     /// this prim index. If no such node exists, returns an invalid PcpNodeRef.
170     PCP_API
171     PcpNodeRef GetNodeProvidingSpec(const SdfPrimSpecHandle& primSpec) const;
172 
173     /// Returns the node that brings opinions from the Sd prim spec at \p layer
174     /// and \p path into this prim index. If no such node exists, returns an
175     /// invalid PcpNodeRef.
176     PCP_API
177     PcpNodeRef GetNodeProvidingSpec(
178         const SdfLayerHandle& layer, const SdfPath& path) const;
179 
180     /// @}
181 
182     /// \name Diagnostics
183     /// @{
184 
185     /// Return the list of errors local to this prim.
GetLocalErrors()186     PcpErrorVector GetLocalErrors() const {
187         return _localErrors ? *_localErrors.get() : PcpErrorVector();
188     }
189 
190     /// Prints various statistics about this prim index.
191     PCP_API
192     void PrintStatistics() const;
193 
194     /// Dump the prim index contents to a string.
195     ///
196     /// If \p includeInheritOriginInfo is \c true, output for implied inherit
197     /// nodes will include information about the originating inherit node.
198     /// If \p includeMaps is \c true, output for each node will include the
199     /// mappings to the parent and root node.
200     PCP_API
201     std::string DumpToString(
202         bool includeInheritOriginInfo = true,
203         bool includeMaps = true) const;
204 
205     /// Dump the prim index in dot format to the file named \p filename.
206     /// See Dump(...) for information regarding arguments.
207     PCP_API
208     void DumpToDotGraph(
209         const std::string& filename,
210         bool includeInheritOriginInfo = true,
211         bool includeMaps = false) const;
212 
213     /// @}
214 
215 
216     /// \name Derived computations
217     /// @{
218 
219     /// Compute the prim child names for the given path. \p errors will
220     /// contain any errors encountered while performing this operation.
221     PCP_API
222     void ComputePrimChildNames(TfTokenVector *nameOrder,
223                                PcpTokenSet *prohibitedNameSet) const;
224 
225     /// Compute the prim property names for the given path. \p errors will
226     /// contain any errors encountered while performing this operation.  The
227     /// \p nameOrder vector must not contain any duplicate entries.
228     PCP_API
229     void ComputePrimPropertyNames(TfTokenVector *nameOrder) const;
230 
231     /// Compose the authored prim variant selections.
232     ///
233     /// These are the variant selections expressed in scene description.
234     /// Note that these selections may not have actually been applied,
235     /// if they are invalid.
236     ///
237     /// \note This result is not cached, but computed each time.
238     PCP_API
239     SdfVariantSelectionMap ComposeAuthoredVariantSelections() const;
240 
241     /// Return the variant selection applied for the named variant set.
242     /// If none was applied, this returns an empty string.
243     /// This can be different from the authored variant selection;
244     /// for example, if the authored selection is invalid.
245     PCP_API
246     std::string GetSelectionAppliedForVariantSet(
247         const std::string &variantSet) const;
248 
249     /// @}
250 
251 private:
252     friend class PcpPrimIterator;
253     friend struct Pcp_PrimIndexer;
254     friend void Pcp_RescanForSpecs(PcpPrimIndex*, bool usd,
255                                    bool updateHasSpecs);
256 
257     // The node graph representing the compositional structure of this prim.
258     PcpPrimIndex_GraphRefPtr _graph;
259 
260     // The prim stack.  This is just a derived structure representing
261     // a cached strong-to-weak traversal of the graph collecting specs.
262     Pcp_CompressedSdSiteVector _primStack;
263 
264     // List of errors local to this prim, encountered during computation.
265     // NULL if no errors were found (the expected common case).
266     std::unique_ptr<PcpErrorVector> _localErrors;
267 };
268 
269 /// Free function version for generic code and ADL.
swap(PcpPrimIndex & l,PcpPrimIndex & r)270 inline void swap(PcpPrimIndex &l, PcpPrimIndex &r) { l.swap(r); }
271 
272 /// \class PcpPrimIndexOutputs
273 ///
274 /// Outputs of the prim indexing procedure.
275 ///
276 class PcpPrimIndexOutputs
277 {
278 public:
279     /// Enumerator whose enumerants describe the payload state of this prim
280     /// index.  NoPayload if the index has no payload arcs, otherwise whether
281     /// payloads were included or excluded, and if done so by consulting either
282     /// the cache's payload include set, or determined by a payload predicate.
283     enum PayloadState { NoPayload,
284                         IncludedByIncludeSet, ExcludedByIncludeSet,
285                         IncludedByPredicate, ExcludedByPredicate };
286 
287     /// Prim index describing the composition structure for the associated
288     /// prim.
289     PcpPrimIndex primIndex;
290 
291     /// List of all errors encountered during indexing.
292     PcpErrorVector allErrors;
293 
294     /// Indicates the payload state of this index.  See documentation for
295     /// PayloadState enum for more information.
296     PayloadState payloadState = NoPayload;
297 
298     /// A list of names of fields that were composed to generate dynamic file
299     /// format arguments for a node in primIndex. These are not necessarily
300     /// fields that had values, but is the list of all fields that a  composed
301     /// value was requested for.
302     PcpDynamicFileFormatDependencyData dynamicFileFormatDependency;
303 
304     /// Swap content with \p r.
swap(PcpPrimIndexOutputs & r)305     inline void swap(PcpPrimIndexOutputs &r) {
306         primIndex.swap(r.primIndex);
307         allErrors.swap(r.allErrors);
308         std::swap(payloadState, r.payloadState);
309         dynamicFileFormatDependency.swap(r.dynamicFileFormatDependency);
310     }
311 
312     /// Appends the outputs from \p childOutputs to this object, using
313     /// \p arcToParent to connect \p childOutputs' prim index to this object's
314     /// prim index.
315     ///
316     /// Returns the node in this object's prim index corresponding to the root
317     /// node of \p childOutputs' prim index.
318     PcpNodeRef Append(PcpPrimIndexOutputs&& childOutputs,
319                       const PcpArc& arcToParent,
320                       PcpErrorBasePtr *error);
321 };
322 
323 /// Free function version for generic code and ADL.
swap(PcpPrimIndexOutputs & l,PcpPrimIndexOutputs & r)324 inline void swap(PcpPrimIndexOutputs &l, PcpPrimIndexOutputs &r) { l.swap(r); }
325 
326 /// \class PcpPrimIndexInputs
327 ///
328 /// Inputs for the prim indexing procedure.
329 ///
330 class PcpPrimIndexInputs {
331 public:
PcpPrimIndexInputs()332     PcpPrimIndexInputs()
333         : cache(nullptr)
334         , variantFallbacks(nullptr)
335         , includedPayloads(nullptr)
336         , includedPayloadsMutex(nullptr)
337         , parentIndex(nullptr)
338         , cull(true)
339         , usd(false)
340     { }
341 
342     /// Returns true if prim index computations using this parameters object
343     /// would be equivalent to computations using \p params.
344     bool IsEquivalentTo(const PcpPrimIndexInputs& params) const;
345 
346     /// If supplied, the given PcpCache will be used where possible to compute
347     /// needed intermediate results.
Cache(PcpCache * cache_)348     PcpPrimIndexInputs& Cache(PcpCache* cache_)
349     { cache = cache_; return *this; }
350 
351     /// Ordered list of variant names to use for the "standin" variant set
352     /// if there is no authored opinion in scene description.
VariantFallbacks(const PcpVariantFallbackMap * map)353     PcpPrimIndexInputs& VariantFallbacks(const PcpVariantFallbackMap* map)
354     { variantFallbacks = map; return *this; }
355 
356     /// Set of paths to prims that should have their payloads included
357     /// during composition.
358     using PayloadSet = std::unordered_set<SdfPath, SdfPath::Hash>;
IncludedPayloads(const PayloadSet * payloadSet)359     PcpPrimIndexInputs& IncludedPayloads(const PayloadSet* payloadSet)
360     { includedPayloads = payloadSet; return *this; }
361 
362     /// Optional mutex for accessing includedPayloads.
IncludedPayloadsMutex(tbb::spin_rw_mutex * mutex)363     PcpPrimIndexInputs &IncludedPayloadsMutex(tbb::spin_rw_mutex *mutex)
364     { includedPayloadsMutex = mutex; return *this; }
365 
366     /// Optional predicate evaluated when a not-yet-included payload is
367     /// discovered while indexing.  If the predicate returns true, indexing
368     /// includes the payload and sets the includedDiscoveredPayload bit in the
369     /// outputs.
IncludePayloadPredicate(std::function<bool (const SdfPath &)> predicate)370     PcpPrimIndexInputs &IncludePayloadPredicate(
371         std::function<bool (const SdfPath &)> predicate)
372     { includePayloadPredicate = predicate; return *this; }
373 
374     /// Whether subtrees that contribute no opinions should be culled
375     /// from the index.
376     PcpPrimIndexInputs& Cull(bool doCulling = true)
377     { cull = doCulling; return *this; }
378 
379     /// Whether the prim stack should be computed, and
380     /// whether relocates, inherits, permissions, symmetry, or payloads should
381     /// be considered during prim index computation,
382     PcpPrimIndexInputs& USD(bool doUSD = true)
383     { usd = doUSD; return *this; }
384 
385     /// The file format target for scene description layers encountered during
386     /// prim index computation.
FileFormatTarget(const std::string & target)387     PcpPrimIndexInputs& FileFormatTarget(const std::string& target)
388     { fileFormatTarget = target; return *this; }
389 
390 // private:
391     PcpCache* cache;
392     const PcpVariantFallbackMap* variantFallbacks;
393     const PayloadSet* includedPayloads;
394     tbb::spin_rw_mutex *includedPayloadsMutex;
395     std::function<bool (const SdfPath &)> includePayloadPredicate;
396     const PcpPrimIndex *parentIndex;
397     std::string fileFormatTarget;
398     bool cull;
399     bool usd;
400 };
401 
402 /// Compute an index for the given path. \p errors will contain any errors
403 /// encountered while performing this operation.
404 PCP_API
405 void
406 PcpComputePrimIndex(
407     const SdfPath& primPath,
408     const PcpLayerStackPtr& layerStack,
409     const PcpPrimIndexInputs& inputs,
410     PcpPrimIndexOutputs* outputs,
411     ArResolver* pathResolver = NULL);
412 
413 /// Returns true if the 'new' default standin behavior is enabled.
414 PCP_API
415 bool
416 PcpIsNewDefaultStandinBehaviorEnabled();
417 
418 // Sets the prim stack in \p index.
419 void
420 Pcp_RescanForSpecs(PcpPrimIndex* index, bool usd);
421 
422 // Returns true if \p index should be recomputed due to changes to
423 // any computed asset paths that were used to find or open layers
424 // when originally composing \p index. This may be due to scene
425 // description changes or external changes to asset resolution that
426 // may affect the computation of those asset paths.
427 bool
428 Pcp_NeedToRecomputeDueToAssetPathChange(const PcpPrimIndex& index);
429 
430 PXR_NAMESPACE_CLOSE_SCOPE
431 
432 #endif // PXR_USD_PCP_PRIM_INDEX_H
433