Loading...
Searching...
No Matches
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 HasClassSpecifier() const {
130 return _flags[Usd_PrimHasClassSpecifierFlag];
131 }
132
134 bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; }
135
139 bool MayHaveOpinionsInClips() const { return _flags[Usd_PrimClipsFlag]; }
140
142 USD_API
143 SdfSpecifier GetSpecifier() const;
144
145 // --------------------------------------------------------------------- //
147 // --------------------------------------------------------------------- //
148
150 USD_API
151 Usd_PrimDataConstPtr GetParent() const;
152
153 // --------------------------------------------------------------------- //
154 // PrimIndex access.
155 // --------------------------------------------------------------------- //
156
173 USD_API
174 const class PcpPrimIndex &GetPrimIndex() const;
175
182 USD_API
183 const class PcpPrimIndex &GetSourcePrimIndex() const;
184
185 // --------------------------------------------------------------------- //
186 // Tree Structure
187 // --------------------------------------------------------------------- //
188
189 // Return this prim data's first child if it has one, nullptr otherwise.
190 Usd_PrimDataPtr GetFirstChild() const { return _firstChild; }
191
192 // Return this prim data's next sibling if it has one, nullptr otherwise.
193 Usd_PrimDataPtr GetNextSibling() const {
194 return !_nextSiblingOrParent.BitsAs<bool>() ?
195 _nextSiblingOrParent.Get() : nullptr;
196 }
197
198 // Return this prim data's parent if this prim data is the last in its chain
199 // of siblings. That is, if the _nextSiblingOrParent field is pointing to
200 // its parent. Return nullptr otherwise.
201 Usd_PrimDataPtr GetParentLink() const {
202 return _nextSiblingOrParent.BitsAs<bool>() ?
203 _nextSiblingOrParent.Get() : nullptr;
204 }
205
206 // Return the next prim data "to the right" of this one. That is, this
207 // prim's next sibling if it has one, otherwise the next sibling of the
208 // nearest ancestor with a sibling, if there is one, otherwise null.
209 inline Usd_PrimDataPtr GetNextPrim() const {
210 if (Usd_PrimDataPtr sibling = GetNextSibling())
211 return sibling;
212 for (Usd_PrimDataPtr p = GetParentLink(); p; p = p->GetParentLink()) {
213 if (Usd_PrimDataPtr sibling = p->GetNextSibling())
214 return sibling;
215 }
216 return nullptr;
217 }
218
219 // Return the prim data at \p path. If \p path indicates a prim
220 // beneath an instance, return the prim data for the corresponding
221 // prim in the instance's prototype.
222 USD_API Usd_PrimDataConstPtr
223 GetPrimDataAtPathOrInPrototype(const SdfPath &path) const;
224
225 // --------------------------------------------------------------------- //
226 // Instancing
227 // --------------------------------------------------------------------- //
228
231 bool IsInstance() const { return _flags[Usd_PrimInstanceFlag]; }
232
234 bool IsPrototype() const {
235 return IsInPrototype() && GetPath().IsRootPrimPath();
236 }
237
240 bool IsInPrototype() const { return _flags[Usd_PrimPrototypeFlag]; }
241
244 USD_API Usd_PrimDataConstPtr GetPrototype() const;
245
246 // --------------------------------------------------------------------- //
247 // Private Members
248 // --------------------------------------------------------------------- //
249private:
250
251 USD_API
252 Usd_PrimData(UsdStage *stage, const SdfPath& path);
253 USD_API
254 ~Usd_PrimData();
255
256 // Compute and store type info and cached flags.
257 void _ComposeAndCacheFlags(
258 Usd_PrimDataConstPtr parent, bool isPrototypePrim);
259
260 // Flags direct access for Usd_PrimFlagsPredicate.
261 friend class Usd_PrimFlagsPredicate;
262 const Usd_PrimFlagBits &_GetFlags() const {
263 return _flags;
264 }
265
266 // --------------------------------------------------------------------- //
267 // Prim Children
268 // --------------------------------------------------------------------- //
269
270 // Composes the prim children, reporting errors as they occur. Returns true
271 // on success false on failure.
272 bool _ComposePrimChildNames(TfTokenVector* nameOrder);
273
274 void _SetSiblingLink(Usd_PrimDataPtr sibling) {
275 _nextSiblingOrParent.Set(sibling, /* isParent */ false);
276 }
277
278 void _SetParentLink(Usd_PrimDataPtr parent) {
279 _nextSiblingOrParent.Set(parent, /* isParent */ true);
280 }
281
282 // Set the dead bit on this prim data object.
283 void _MarkDead() {
284 _flags[Usd_PrimDeadFlag] = true;
285 _stage = nullptr;
286 _primIndex = nullptr;
287 }
288
289 // Return true if this prim's dead flag is set, false otherwise.
290 bool _IsDead() const { return _flags[Usd_PrimDeadFlag]; }
291
292 // Set whether this prim or any of its namespace ancestors had clips
293 // specified.
294 void _SetMayHaveOpinionsInClips(bool hasClips) {
295 _flags[Usd_PrimClipsFlag] = hasClips;
296 }
297
298 inline class Usd_PrimDataSiblingIterator _ChildrenBegin() const;
299 inline class Usd_PrimDataSiblingIterator _ChildrenEnd() const;
300
301 inline class Usd_PrimDataSubtreeIterator _SubtreeBegin() const;
302 inline class Usd_PrimDataSubtreeIterator _SubtreeEnd() const;
303
304 // Data members.
305 UsdStage *_stage;
306 const PcpPrimIndex *_primIndex;
307 SdfPath _path;
308 const UsdPrimTypeInfo *_primTypeInfo;
309 Usd_PrimData *_firstChild;
310 TfPointerAndBits<Usd_PrimData> _nextSiblingOrParent;
311 mutable std::atomic<int64_t> _refCount;
312 Usd_PrimFlagBits _flags;
313
314 // intrusive_ptr core primitives implementation.
315 friend void TfDelegatedCountIncrement(const Usd_PrimData *prim) noexcept {
316 prim->_refCount.fetch_add(1, std::memory_order_relaxed);
317 }
318 friend void TfDelegatedCountDecrement(const Usd_PrimData *prim) noexcept {
319 if (prim->_refCount.fetch_sub(1, std::memory_order_release) == 1) {
320 // Synchronize with the release decrements of all other owners so
321 // their prior accesses to *ptr happen-before its destruction.
322 std::atomic_thread_fence(std::memory_order_acquire);
323 delete prim;
324 }
325 }
326
327 USD_API
328 friend void Usd_ThrowExpiredPrimAccessError(Usd_PrimData const *p);
329 friend std::string
330 Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath);
331
332 friend inline bool Usd_IsDead(Usd_PrimData const *p) {
333 return p->_IsDead();
334 }
335
336 friend class UsdPrim;
337 friend class UsdStage;
338};
339
340// Sibling iterator class.
341class Usd_PrimDataSiblingIterator {
342 using _UnderylingIterator = Usd_PrimData*;
343public:
344 using iterator_category = std::forward_iterator_tag;
345 using value_type = Usd_PrimData*;
346 using reference = Usd_PrimData*;
347 using pointer = void;
348 using difference_type = std::ptrdiff_t;
349
350 // Default ctor.
351 Usd_PrimDataSiblingIterator() = default;
352
353 reference operator*() const { return _underlyingIterator; }
354
355 // pre-increment
356 Usd_PrimDataSiblingIterator& operator++() {
357 increment();
358 return *this;
359 }
360
361 // post-increment
362 Usd_PrimDataSiblingIterator operator++(int) {
363 Usd_PrimDataSiblingIterator result = *this;
364 increment();
365 return result;
366 }
367
368 bool operator==(const Usd_PrimDataSiblingIterator& other) const {
369 return _underlyingIterator == other._underlyingIterator;
370 }
371
372 bool operator!=(const Usd_PrimDataSiblingIterator& other) const {
373 return _underlyingIterator != other._underlyingIterator;
374 }
375
376private:
377 friend class Usd_PrimData;
378
379 // Constructor used by Prim.
380 Usd_PrimDataSiblingIterator(const _UnderylingIterator &i)
381 : _underlyingIterator(i) {}
382
383 void increment() {
384 _underlyingIterator = _underlyingIterator->GetNextSibling();
385 }
386
387 _UnderylingIterator _underlyingIterator = nullptr;
388};
389
390Usd_PrimDataSiblingIterator
391Usd_PrimData::_ChildrenBegin() const
392{
393 return Usd_PrimDataSiblingIterator(_firstChild);
394}
395
396Usd_PrimDataSiblingIterator
397Usd_PrimData::_ChildrenEnd() const
398{
399 return Usd_PrimDataSiblingIterator(0);
400}
401
402// Tree iterator class.
403class Usd_PrimDataSubtreeIterator {
404 using _UnderlyingIterator = Usd_PrimData*;
405public:
406 using iterator_category = std::forward_iterator_tag;
407 using value_type = Usd_PrimData*;
408 using reference = Usd_PrimData*;
409 using pointer = void;
410 using difference_type = std::ptrdiff_t;
411
412 // Default ctor.
413 Usd_PrimDataSubtreeIterator() = default;
414
415 reference operator*() const { return _underlyingIterator; }
416
417 // pre-increment
418 Usd_PrimDataSubtreeIterator& operator++() {
419 increment();
420 return *this;
421 }
422
423 // post-increment
424 Usd_PrimDataSubtreeIterator operator++(int) {
425 Usd_PrimDataSubtreeIterator result = *this;
426 increment();
427 return result;
428 }
429
430 bool operator==(const Usd_PrimDataSubtreeIterator& other) const {
431 return _underlyingIterator == other._underlyingIterator;
432 }
433
434 bool operator!=(const Usd_PrimDataSubtreeIterator& other) const {
435 return _underlyingIterator != other._underlyingIterator;
436 }
437
438private:
439 friend class Usd_PrimData;
440 friend class UsdPrimSubtreeIterator;
441
442 // Constructor used by Prim.
443 Usd_PrimDataSubtreeIterator(const _UnderlyingIterator &i)
444 : _underlyingIterator(i) {}
445
446 void increment() {
447 _underlyingIterator = _underlyingIterator->GetFirstChild() ?
448 _underlyingIterator->GetFirstChild() :
449 _underlyingIterator->GetNextPrim();
450 }
451
452 _UnderlyingIterator _underlyingIterator = nullptr;
453};
454
455Usd_PrimDataSubtreeIterator
456Usd_PrimData::_SubtreeBegin() const
457{
458 return Usd_PrimDataSubtreeIterator(
459 _firstChild ? _firstChild : GetNextPrim());
460}
461
462Usd_PrimDataSubtreeIterator
463Usd_PrimData::_SubtreeEnd() const
464{
465 return Usd_PrimDataSubtreeIterator(GetNextPrim());
466}
467
468// Helpers for instance proxies.
469
470// Return true if the prim with prim data \p p and proxy prim path
471// \p proxyPrimPath represents an instance proxy.
472template <class PrimDataPtr>
473inline bool
474Usd_IsInstanceProxy(const PrimDataPtr &p, const SdfPath &proxyPrimPath)
475{
476 return !proxyPrimPath.IsEmpty();
477}
478
479// Helpers for subtree traversals.
480
481// Create a predicate based on \p pred for use when traversing the
482// siblings or descendants of the prim with prim data \p p and proxy
483// prim path \p proxyPrimPath. This is used by prim traversal functions
484// like UsdPrim::GetFilteredChildren, UsdPrim::GetFilteredDescendants,
485// UsdPrim::GetFilteredNextSibling, and UsdPrimRange.
486template <class PrimDataPtr>
487inline Usd_PrimFlagsPredicate
488Usd_CreatePredicateForTraversal(const PrimDataPtr &p,
489 const SdfPath &proxyPrimPath,
490 Usd_PrimFlagsPredicate pred)
491{
492 // Don't allow traversals beneath instances unless the client has
493 // explicitly requested it or the starting point is already beneath
494 // an instance (i.e., the starting point is an instance proxy).
495 if (!Usd_IsInstanceProxy(p, proxyPrimPath) &&
496 !pred.IncludeInstanceProxiesInTraversal()) {
497 pred.TraverseInstanceProxies(false);
498 }
499 return pred;
500}
501
502// Move \p p to its parent. If \p proxyPrimPath is not empty, set it to
503// its parent path. If after this \p p is a prototype prim, move \p p to
504// the prim indicated by \p proxyPrimPath. If \p p's path is then equal
505// to \p proxyPrimPath, set \p proxyPrimPath to the empty path.
506template <class PrimDataPtr>
507inline void
508Usd_MoveToParent(PrimDataPtr &p, SdfPath &proxyPrimPath)
509{
510 p = p->GetParent();
511
512 if (!proxyPrimPath.IsEmpty()) {
513 proxyPrimPath = proxyPrimPath.GetParentPath();
514
515 if (p && p->IsPrototype()) {
516 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
517 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
518 p->GetPath() == proxyPrimPath) {
519 proxyPrimPath = SdfPath();
520 }
521 }
522 }
523}
524
525// Search for the next sibling that matches \p pred (up to \p end). If such a
526// sibling exists, move \p p to it and return false. If no such sibling exists
527// then move \p p to its parent and return true. If \p end is reached while
528// looking for siblings, move \p p to \p end and return false.
529//
530// If \p proxyPrimPath is not empty, update it based on the new value of \p p:
531// - If \p p was moved to \p end, set \p proxyPrimPath to the empty path.
532// - If \p p was moved to a sibling, set the prim name for \p proxyPrimPath
533// to the sibling's name.
534// - If \p p was moved to a parent, set \p proxyPrimPath and \p p the same
535// way as Usd_MoveToParent.
536template <class PrimDataPtr>
537inline bool
538Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
539 PrimDataPtr end,
540 const Usd_PrimFlagsPredicate &pred)
541{
542 // Either all siblings are instance proxies or none are. We can just
543 // compute this once and reuse it as we scan for the next sibling.
544 const bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
545
546 PrimDataPtr next = p->GetNextSibling();
547 while (next && next != end &&
548 !Usd_EvalPredicate(pred, next, isInstanceProxy)) {
549 p = next;
550 next = p->GetNextSibling();
551 }
552 p = next ? next : p->GetParentLink();
553
554 if (!proxyPrimPath.IsEmpty()) {
555 if (p == end) {
556 proxyPrimPath = SdfPath();
557 }
558 else if (p == next) {
559 proxyPrimPath =
560 proxyPrimPath.GetParentPath().AppendChild(p->GetName());
561 }
562 else {
563 proxyPrimPath = proxyPrimPath.GetParentPath();
564 if (p && p->IsPrototype()) {
565 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
566 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
567 p->GetPath() == proxyPrimPath) {
568 proxyPrimPath = SdfPath();
569 }
570 }
571 }
572 }
573
574 // Return true if we successfully moved to a parent, otherwise false.
575 return !next && p;
576}
577
578// Convenience method for calling the above with \p end = \c nullptr.
579template <class PrimDataPtr>
580inline bool
581Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
582 const Usd_PrimFlagsPredicate &pred)
583{
584 return Usd_MoveToNextSiblingOrParent(p, proxyPrimPath,
585 PrimDataPtr(nullptr), pred);
586}
587
588// Search for the first direct child of \p p that matches \p pred (up to
589// \p end). If the given \p p is an instance, search for direct children
590// on the corresponding prototype prim. If such a direct child exists,
591// move \p p to it, and return true. Otherwise leave the iterator
592// unchanged and return false.
593template <class PrimDataPtr>
594inline bool
595Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
596 PrimDataPtr end,
597 const Usd_PrimFlagsPredicate &pred)
598{
599 bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
600
601 PrimDataPtr src = p;
602 if (src->IsInstance()) {
603 src = src->GetPrototype();
604 isInstanceProxy = true;
605 }
606
607 if (PrimDataPtr child = src->GetFirstChild()) {
608 if (isInstanceProxy) {
609 proxyPrimPath = proxyPrimPath.IsEmpty() ?
610 p->GetPath().AppendChild(child->GetName()) :
611 proxyPrimPath.AppendChild(child->GetName());
612 }
613
614 p = child;
615
616 if (Usd_EvalPredicate(pred, p, isInstanceProxy) ||
617 !Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, end, pred)) {
618 return true;
619 }
620 }
621 return false;
622}
623
624// Convenience method for calling the above with \p end = \c nullptr.
625template <class PrimDataPtr>
626inline bool
627Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
628 const Usd_PrimFlagsPredicate &pred)
629{
630 return Usd_MoveToChild(p, proxyPrimPath, PrimDataPtr(nullptr), pred);
631}
632
633PXR_NAMESPACE_CLOSE_SCOPE
634
635#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:281
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:405
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:81
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:2543
Class that holds the full type information for a prim.
The outermost container for scene description, which owns and presents composed prims as a scenegraph...
Definition stage.h:135
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:267
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:489
Basic Sdf data types.
SdfSpecifier
An enum that identifies the possible specifiers for an SdfPrimSpec.
Definition types.h:105