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