All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
primData.h
Go to the documentation of this file.
1//
2// Copyright 2016 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_USD_USD_PRIM_DATA_H
8#define PXR_USD_USD_PRIM_DATA_H
9
11
12#include "pxr/pxr.h"
13#include "pxr/usd/usd/api.h"
14#include "pxr/usd/usd/common.h"
16#include "pxr/usd/usd/primDefinition.h"
17#include "pxr/usd/usd/primTypeInfo.h"
18#include "pxr/usd/sdf/types.h"
19
21#include "pxr/base/tf/pointerAndBits.h"
22#include "pxr/base/tf/token.h"
23
24#include "pxr/usd/sdf/path.h"
25
26#include <atomic>
27#include <cstdint>
28#include <vector>
29
30PXR_NAMESPACE_OPEN_SCOPE
31
33
34// Private class that stores cached prim information and defines the prim tree
35// on a UsdStage.
36//
37// Usd_PrimData objects are arranged in a tree structure, represented as a
38// binary tree. See the _firstChild and _nextSiblingOrParent members.
39//
40// UsdStage builds and manages the tree structure of Usd_PrimData objects. The
41// Usd_PrimData objects lifetimes are governed by an internal reference count
42// (see _refCount). Two objects mutate this reference count: UsdStage owns
43// references to all the Usd_PrimData objects that represent the scene graph,
44// and UsdObject (and by inheritance its subclasses) owns a reference to its
45// prim data object via Usd_PrimDataHandle.
46//
47// Usd_PrimData has a 'dead' flag (see _IsDead and _MarkDead). UsdStage sets
48// this when a prim data object is removed from the scene graph.
49// Usd_PrimDataHandle, which is a smart pointer to Usd_PrimData consults this
50// dead flag to determine prim validity, and to issue informative crash messages
51// on invalid use. See USD_CHECK_ALL_PRIM_ACCESSES.
52//
53class Usd_PrimData
54{
55public:
56
57 // --------------------------------------------------------------------- //
59 // --------------------------------------------------------------------- //
60
67 const SdfPath &GetPath() const { return _path; }
68
69 const TfToken &GetName() const { return GetPath().GetNameToken(); }
70
71 UsdStage *GetStage() const { return _stage; }
72
74 const UsdPrimDefinition &GetPrimDefinition() const {
75 return _primTypeInfo->GetPrimDefinition();
76 }
77
80 const TfToken& GetTypeName() const {
81 return _primTypeInfo->GetTypeName();
82 }
83
85 const UsdPrimTypeInfo &GetPrimTypeInfo() const {
86 return *_primTypeInfo;
87 }
88
90 bool IsPseudoRoot() const { return _flags[Usd_PrimPseudoRootFlag]; }
91
94 bool IsActive() const { return _flags[Usd_PrimActiveFlag]; }
95
99 bool IsLoaded() const { return _flags[Usd_PrimLoadedFlag]; }
100
103 bool IsModel() const { return _flags[Usd_PrimModelFlag]; }
104
108 bool IsGroup() const { return _flags[Usd_PrimGroupFlag]; }
109
110 bool IsComponent() const { return _flags[Usd_PrimComponentFlag]; }
111
112 USD_API
113 bool IsSubComponent() const;
114
116 bool IsAbstract() const { return _flags[Usd_PrimAbstractFlag]; }
117
120 bool IsDefined() const { return _flags[Usd_PrimDefinedFlag]; }
121
124 bool HasDefiningSpecifier() const {
125 return _flags[Usd_PrimHasDefiningSpecifierFlag];
126 }
127
129 bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; }
130
134 bool MayHaveOpinionsInClips() const { return _flags[Usd_PrimClipsFlag]; }
135
137 USD_API
138 SdfSpecifier GetSpecifier() const;
139
140 // --------------------------------------------------------------------- //
142 // --------------------------------------------------------------------- //
143
145 USD_API
146 Usd_PrimDataConstPtr GetParent() const;
147
148 // --------------------------------------------------------------------- //
149 // PrimIndex access.
150 // --------------------------------------------------------------------- //
151
168 USD_API
169 const class PcpPrimIndex &GetPrimIndex() const;
170
177 USD_API
178 const class PcpPrimIndex &GetSourcePrimIndex() const;
179
180 // --------------------------------------------------------------------- //
181 // Tree Structure
182 // --------------------------------------------------------------------- //
183
184 // Return this prim data's first child if it has one, nullptr otherwise.
185 Usd_PrimDataPtr GetFirstChild() const { return _firstChild; }
186
187 // Return this prim data's next sibling if it has one, nullptr otherwise.
188 Usd_PrimDataPtr GetNextSibling() const {
189 return !_nextSiblingOrParent.BitsAs<bool>() ?
190 _nextSiblingOrParent.Get() : nullptr;
191 }
192
193 // Return this prim data's parent if this prim data is the last in its chain
194 // of siblings. That is, if the _nextSiblingOrParent field is pointing to
195 // its parent. Return nullptr otherwise.
196 Usd_PrimDataPtr GetParentLink() const {
197 return _nextSiblingOrParent.BitsAs<bool>() ?
198 _nextSiblingOrParent.Get() : nullptr;
199 }
200
201 // Return the next prim data "to the right" of this one. That is, this
202 // prim's next sibling if it has one, otherwise the next sibling of the
203 // nearest ancestor with a sibling, if there is one, otherwise null.
204 inline Usd_PrimDataPtr GetNextPrim() const {
205 if (Usd_PrimDataPtr sibling = GetNextSibling())
206 return sibling;
207 for (Usd_PrimDataPtr p = GetParentLink(); p; p = p->GetParentLink()) {
208 if (Usd_PrimDataPtr sibling = p->GetNextSibling())
209 return sibling;
210 }
211 return nullptr;
212 }
213
214 // Return the prim data at \p path. If \p path indicates a prim
215 // beneath an instance, return the prim data for the corresponding
216 // prim in the instance's prototype.
217 USD_API Usd_PrimDataConstPtr
218 GetPrimDataAtPathOrInPrototype(const SdfPath &path) const;
219
220 // --------------------------------------------------------------------- //
221 // Instancing
222 // --------------------------------------------------------------------- //
223
226 bool IsInstance() const { return _flags[Usd_PrimInstanceFlag]; }
227
229 bool IsPrototype() const {
230 return IsInPrototype() && GetPath().IsRootPrimPath();
231 }
232
235 bool IsInPrototype() const { return _flags[Usd_PrimPrototypeFlag]; }
236
239 USD_API Usd_PrimDataConstPtr GetPrototype() const;
240
241 // --------------------------------------------------------------------- //
242 // Private Members
243 // --------------------------------------------------------------------- //
244private:
245
246 USD_API
247 Usd_PrimData(UsdStage *stage, const SdfPath& path);
248 USD_API
249 ~Usd_PrimData();
250
251 // Compute and store type info and cached flags.
252 void _ComposeAndCacheFlags(
253 Usd_PrimDataConstPtr parent, bool isPrototypePrim);
254
255 // Flags direct access for Usd_PrimFlagsPredicate.
256 friend class Usd_PrimFlagsPredicate;
257 const Usd_PrimFlagBits &_GetFlags() const {
258 return _flags;
259 }
260
261 // --------------------------------------------------------------------- //
262 // Prim Children
263 // --------------------------------------------------------------------- //
264
265 // Composes the prim children, reporting errors as they occur. Returns true
266 // on success false on failure.
267 bool _ComposePrimChildNames(TfTokenVector* nameOrder);
268
269 void _SetSiblingLink(Usd_PrimDataPtr sibling) {
270 _nextSiblingOrParent.Set(sibling, /* isParent */ false);
271 }
272
273 void _SetParentLink(Usd_PrimDataPtr parent) {
274 _nextSiblingOrParent.Set(parent, /* isParent */ true);
275 }
276
277 // Set the dead bit on this prim data object.
278 void _MarkDead() {
279 _flags[Usd_PrimDeadFlag] = true;
280 _stage = nullptr;
281 _primIndex = nullptr;
282 }
283
284 // Return true if this prim's dead flag is set, false otherwise.
285 bool _IsDead() const { return _flags[Usd_PrimDeadFlag]; }
286
287 // Set whether this prim or any of its namespace ancestors had clips
288 // specified.
289 void _SetMayHaveOpinionsInClips(bool hasClips) {
290 _flags[Usd_PrimClipsFlag] = hasClips;
291 }
292
293 inline class Usd_PrimDataSiblingIterator _ChildrenBegin() const;
294 inline class Usd_PrimDataSiblingIterator _ChildrenEnd() const;
295
296 inline class Usd_PrimDataSubtreeIterator _SubtreeBegin() const;
297 inline class Usd_PrimDataSubtreeIterator _SubtreeEnd() const;
298
299 // Data members.
300 UsdStage *_stage;
301 const PcpPrimIndex *_primIndex;
302 SdfPath _path;
303 const UsdPrimTypeInfo *_primTypeInfo;
304 Usd_PrimData *_firstChild;
305 TfPointerAndBits<Usd_PrimData> _nextSiblingOrParent;
306 mutable std::atomic<int64_t> _refCount;
307 Usd_PrimFlagBits _flags;
308
309 // intrusive_ptr core primitives implementation.
310 friend void TfDelegatedCountIncrement(const Usd_PrimData *prim) noexcept {
311 prim->_refCount.fetch_add(1, std::memory_order_relaxed);
312 }
313 friend void TfDelegatedCountDecrement(const Usd_PrimData *prim) noexcept {
314 if (prim->_refCount.fetch_sub(1, std::memory_order_release) == 1)
315 delete prim;
316 }
317
318 USD_API
319 friend void Usd_ThrowExpiredPrimAccessError(Usd_PrimData const *p);
320 friend std::string
321 Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath);
322
323 friend inline bool Usd_IsDead(Usd_PrimData const *p) {
324 return p->_IsDead();
325 }
326
327 friend class UsdPrim;
328 friend class UsdStage;
329};
330
331// Sibling iterator class.
332class Usd_PrimDataSiblingIterator {
333 using _UnderylingIterator = Usd_PrimData*;
334public:
335 using iterator_category = std::forward_iterator_tag;
336 using value_type = Usd_PrimData*;
337 using reference = Usd_PrimData*;
338 using pointer = void;
339 using difference_type = std::ptrdiff_t;
340
341 // Default ctor.
342 Usd_PrimDataSiblingIterator() = default;
343
344 reference operator*() const { return _underlyingIterator; }
345
346 // pre-increment
347 Usd_PrimDataSiblingIterator& operator++() {
348 increment();
349 return *this;
350 }
351
352 // post-increment
353 Usd_PrimDataSiblingIterator operator++(int) {
354 Usd_PrimDataSiblingIterator result = *this;
355 increment();
356 return result;
357 }
358
359 bool operator==(const Usd_PrimDataSiblingIterator& other) const {
360 return _underlyingIterator == other._underlyingIterator;
361 }
362
363 bool operator!=(const Usd_PrimDataSiblingIterator& other) const {
364 return _underlyingIterator != other._underlyingIterator;
365 }
366
367private:
368 friend class Usd_PrimData;
369
370 // Constructor used by Prim.
371 Usd_PrimDataSiblingIterator(const _UnderylingIterator &i)
372 : _underlyingIterator(i) {}
373
374 void increment() {
375 _underlyingIterator = _underlyingIterator->GetNextSibling();
376 }
377
378 _UnderylingIterator _underlyingIterator = nullptr;
379};
380
381Usd_PrimDataSiblingIterator
382Usd_PrimData::_ChildrenBegin() const
383{
384 return Usd_PrimDataSiblingIterator(_firstChild);
385}
386
387Usd_PrimDataSiblingIterator
388Usd_PrimData::_ChildrenEnd() const
389{
390 return Usd_PrimDataSiblingIterator(0);
391}
392
393// Tree iterator class.
394class Usd_PrimDataSubtreeIterator {
395 using _UnderlyingIterator = Usd_PrimData*;
396public:
397 using iterator_category = std::forward_iterator_tag;
398 using value_type = Usd_PrimData*;
399 using reference = Usd_PrimData*;
400 using pointer = void;
401 using difference_type = std::ptrdiff_t;
402
403 // Default ctor.
404 Usd_PrimDataSubtreeIterator() = default;
405
406 reference operator*() const { return _underlyingIterator; }
407
408 // pre-increment
409 Usd_PrimDataSubtreeIterator& operator++() {
410 increment();
411 return *this;
412 }
413
414 // post-increment
415 Usd_PrimDataSubtreeIterator operator++(int) {
416 Usd_PrimDataSubtreeIterator result = *this;
417 increment();
418 return result;
419 }
420
421 bool operator==(const Usd_PrimDataSubtreeIterator& other) const {
422 return _underlyingIterator == other._underlyingIterator;
423 }
424
425 bool operator!=(const Usd_PrimDataSubtreeIterator& other) const {
426 return _underlyingIterator != other._underlyingIterator;
427 }
428
429private:
430 friend class Usd_PrimData;
431 friend class UsdPrimSubtreeIterator;
432
433 // Constructor used by Prim.
434 Usd_PrimDataSubtreeIterator(const _UnderlyingIterator &i)
435 : _underlyingIterator(i) {}
436
437 void increment() {
438 _underlyingIterator = _underlyingIterator->GetFirstChild() ?
439 _underlyingIterator->GetFirstChild() :
440 _underlyingIterator->GetNextPrim();
441 }
442
443 _UnderlyingIterator _underlyingIterator = nullptr;
444};
445
446Usd_PrimDataSubtreeIterator
447Usd_PrimData::_SubtreeBegin() const
448{
449 return Usd_PrimDataSubtreeIterator(
450 _firstChild ? _firstChild : GetNextPrim());
451}
452
453Usd_PrimDataSubtreeIterator
454Usd_PrimData::_SubtreeEnd() const
455{
456 return Usd_PrimDataSubtreeIterator(GetNextPrim());
457}
458
459// Helpers for instance proxies.
460
461// Return true if the prim with prim data \p p and proxy prim path
462// \p proxyPrimPath represents an instance proxy.
463template <class PrimDataPtr>
464inline bool
465Usd_IsInstanceProxy(const PrimDataPtr &p, const SdfPath &proxyPrimPath)
466{
467 return !proxyPrimPath.IsEmpty();
468}
469
470// Helpers for subtree traversals.
471
472// Create a predicate based on \p pred for use when traversing the
473// siblings or descendants of the prim with prim data \p p and proxy
474// prim path \p proxyPrimPath. This is used by prim traversal functions
475// like UsdPrim::GetFilteredChildren, UsdPrim::GetFilteredDescendants,
476// UsdPrim::GetFilteredNextSibling, and UsdPrimRange.
477template <class PrimDataPtr>
478inline Usd_PrimFlagsPredicate
479Usd_CreatePredicateForTraversal(const PrimDataPtr &p,
480 const SdfPath &proxyPrimPath,
481 Usd_PrimFlagsPredicate pred)
482{
483 // Don't allow traversals beneath instances unless the client has
484 // explicitly requested it or the starting point is already beneath
485 // an instance (i.e., the starting point is an instance proxy).
486 if (!Usd_IsInstanceProxy(p, proxyPrimPath) &&
487 !pred.IncludeInstanceProxiesInTraversal()) {
488 pred.TraverseInstanceProxies(false);
489 }
490 return pred;
491}
492
493// Move \p p to its parent. If \p proxyPrimPath is not empty, set it to
494// its parent path. If after this \p p is a prototype prim, move \p p to
495// the prim indicated by \p proxyPrimPath. If \p p's path is then equal
496// to \p proxyPrimPath, set \p proxyPrimPath to the empty path.
497template <class PrimDataPtr>
498inline void
499Usd_MoveToParent(PrimDataPtr &p, SdfPath &proxyPrimPath)
500{
501 p = p->GetParent();
502
503 if (!proxyPrimPath.IsEmpty()) {
504 proxyPrimPath = proxyPrimPath.GetParentPath();
505
506 if (p && p->IsPrototype()) {
507 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
508 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
509 p->GetPath() == proxyPrimPath) {
510 proxyPrimPath = SdfPath();
511 }
512 }
513 }
514}
515
516// Search for the next sibling that matches \p pred (up to \p end). If such a
517// sibling exists, move \p p to it and return false. If no such sibling exists
518// then move \p p to its parent and return true. If \p end is reached while
519// looking for siblings, move \p p to \p end and return false.
520//
521// If \p proxyPrimPath is not empty, update it based on the new value of \p p:
522// - If \p p was moved to \p end, set \p proxyPrimPath to the empty path.
523// - If \p p was moved to a sibling, set the prim name for \p proxyPrimPath
524// to the sibling's name.
525// - If \p p was moved to a parent, set \p proxyPrimPath and \p p the same
526// way as Usd_MoveToParent.
527template <class PrimDataPtr>
528inline bool
529Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
530 PrimDataPtr end,
531 const Usd_PrimFlagsPredicate &pred)
532{
533 // Either all siblings are instance proxies or none are. We can just
534 // compute this once and reuse it as we scan for the next sibling.
535 const bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
536
537 PrimDataPtr next = p->GetNextSibling();
538 while (next && next != end &&
539 !Usd_EvalPredicate(pred, next, isInstanceProxy)) {
540 p = next;
541 next = p->GetNextSibling();
542 }
543 p = next ? next : p->GetParentLink();
544
545 if (!proxyPrimPath.IsEmpty()) {
546 if (p == end) {
547 proxyPrimPath = SdfPath();
548 }
549 else if (p == next) {
550 proxyPrimPath =
551 proxyPrimPath.GetParentPath().AppendChild(p->GetName());
552 }
553 else {
554 proxyPrimPath = proxyPrimPath.GetParentPath();
555 if (p && p->IsPrototype()) {
556 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
557 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
558 p->GetPath() == proxyPrimPath) {
559 proxyPrimPath = SdfPath();
560 }
561 }
562 }
563 }
564
565 // Return true if we successfully moved to a parent, otherwise false.
566 return !next && p;
567}
568
569// Convenience method for calling the above with \p end = \c nullptr.
570template <class PrimDataPtr>
571inline bool
572Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
573 const Usd_PrimFlagsPredicate &pred)
574{
575 return Usd_MoveToNextSiblingOrParent(p, proxyPrimPath,
576 PrimDataPtr(nullptr), pred);
577}
578
579// Search for the first direct child of \p p that matches \p pred (up to
580// \p end). If the given \p p is an instance, search for direct children
581// on the corresponding prototype prim. If such a direct child exists,
582// move \p p to it, and return true. Otherwise leave the iterator
583// unchanged and return false.
584template <class PrimDataPtr>
585inline bool
586Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
587 PrimDataPtr end,
588 const Usd_PrimFlagsPredicate &pred)
589{
590 bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
591
592 PrimDataPtr src = p;
593 if (src->IsInstance()) {
594 src = src->GetPrototype();
595 isInstanceProxy = true;
596 }
597
598 if (PrimDataPtr child = src->GetFirstChild()) {
599 if (isInstanceProxy) {
600 proxyPrimPath = proxyPrimPath.IsEmpty() ?
601 p->GetPath().AppendChild(child->GetName()) :
602 proxyPrimPath.AppendChild(child->GetName());
603 }
604
605 p = child;
606
607 if (Usd_EvalPredicate(pred, p, isInstanceProxy) ||
608 !Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, end, pred)) {
609 return true;
610 }
611 }
612 return false;
613}
614
615// Convenience method for calling the above with \p end = \c nullptr.
616template <class PrimDataPtr>
617inline bool
618Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
619 const Usd_PrimFlagsPredicate &pred)
620{
621 return Usd_MoveToChild(p, proxyPrimPath, PrimDataPtr(nullptr), pred);
622}
623
624PXR_NAMESPACE_CLOSE_SCOPE
625
626#endif // PXR_USD_USD_PRIM_DATA_H
PcpPrimIndex is an index of the all sites of scene description that contribute opinions to a specific...
Definition: primIndex.h:62
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:274
SDF_API SdfPath GetParentPath() const
Return the path that identifies this path's namespace parent.
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:398
SDF_API SdfPath AppendChild(TfToken const &childName) const
Creates a path by appending an element for childName to this path.
This class stores a T * and a small integer in the space of a T *.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
Class representing the builtin definition of a prim given the schemas registered in the schema regist...
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a "Prim" as ...
Definition: prim.h:117
Forward traversal iterator of sibling UsdPrim s.
Definition: prim.h:2524
Class that holds the full type information for a prim.
Definition: primTypeInfo.h:31
The outermost container for scene description, which owns and presents composed prims as a scenegraph...
Definition: stage.h:136
Standard pointer typedefs.
#define TF_DECLARE_WEAK_PTRS(type)
Define standard weak pointer types.
Definition: declarePtrs.h:45
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:440
Basic Sdf data types.
SdfSpecifier
An enum that identifies the possible specifiers for an SdfPrimSpec.
Definition: types.h:100