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 #include "pxr/pxr.h"
25 #include "pxr/usd/usd/prim.h"
26 
27 #include "pxr/usd/usd/debugCodes.h"
28 #include "pxr/usd/usd/errors.h"
29 #include "pxr/usd/usd/instanceCache.h"
30 #include "pxr/usd/usd/resolver.h"
31 #include "pxr/usd/usd/stage.h"
32 #include "pxr/usd/usd/tokens.h"
33 #include "pxr/usd/usd/primRange.h"
34 
35 #include "pxr/usd/kind/registry.h"
36 
37 #include "pxr/base/tf/exception.h"
38 #include "pxr/base/tf/stringUtils.h"
39 
40 #include <algorithm>
41 #include <sstream>
42 #include <vector>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 // Static assertion on PrimData size.  We want to be warned when its size
47 // changes.
48 static_assert(sizeof(Usd_PrimData) == 64,
49               "Expected sizeof(Usd_PrimData) == 64");
50 
51 // Usd_PrimData need to be always initialized with a valid type info pointer
_GetEmptyPrimTypeInfo()52 static const UsdPrimTypeInfo *_GetEmptyPrimTypeInfo()
53 {
54     static const UsdPrimTypeInfo *empty = &UsdPrimTypeInfo::GetEmptyPrimType();
55     return empty;
56 }
57 
Usd_PrimData(UsdStage * stage,const SdfPath & path)58 Usd_PrimData::Usd_PrimData(UsdStage *stage, const SdfPath& path)
59     : _stage(stage)
60     , _primIndex(nullptr)
61     , _path(path)
62     , _primTypeInfo(_GetEmptyPrimTypeInfo())
63     , _firstChild(nullptr)
64     , _refCount(0)
65 {
66     if (!stage)
67         TF_FATAL_ERROR("Attempted to construct with null stage");
68 
69     TF_DEBUG(USD_PRIM_LIFETIMES).Msg(
70         "Usd_PrimData::ctor<%s,%s,%s>\n",
71         GetTypeName().GetText(), path.GetText(),
72         _stage->GetRootLayer()->GetIdentifier().c_str());
73 }
74 
~Usd_PrimData()75 Usd_PrimData::~Usd_PrimData() {
76     TF_DEBUG(USD_PRIM_LIFETIMES).Msg(
77         "~Usd_PrimData::dtor<%s,%s,%s>\n",
78         GetTypeName().GetText(), _path.GetText(),
79         _stage ? _stage->GetRootLayer()->GetIdentifier().c_str() :
80         "prim is invalid/expired");
81 }
82 
83 Usd_PrimDataConstPtr
GetParent() const84 Usd_PrimData::GetParent() const
85 {
86     if (Usd_PrimDataPtr parentLink = GetParentLink())
87         return parentLink;
88 
89     SdfPath parent = _path.GetParentPath();
90     return parent == SdfPath::EmptyPath() ?
91         nullptr : _stage->_GetPrimDataAtPath(parent);
92 }
93 
94 const PcpPrimIndex &
GetPrimIndex() const95 Usd_PrimData::GetPrimIndex() const
96 {
97     static const PcpPrimIndex dummyPrimIndex;
98     return ARCH_UNLIKELY(IsPrototype()) ? dummyPrimIndex : *_primIndex;
99 }
100 
101 const PcpPrimIndex &
GetSourcePrimIndex() const102 Usd_PrimData::GetSourcePrimIndex() const
103 {
104     TF_AXIOM(_primIndex);
105     return *_primIndex;
106 }
107 
108 SdfSpecifier
GetSpecifier() const109 Usd_PrimData::GetSpecifier() const
110 {
111     return UsdStage::_GetSpecifier(this);
112 }
113 
114 void
_ComposeAndCacheFlags(Usd_PrimDataConstPtr parent,bool isPrototypePrim)115 Usd_PrimData::_ComposeAndCacheFlags(Usd_PrimDataConstPtr parent,
116                                     bool isPrototypePrim)
117 {
118     // We do not have to clear _flags here since in the pseudo root or instance
119     // prototype case the values never change, and in the ordinary prim case we
120     // set every flag (with the exception of the pseudo root flag which is only
121     // set true for the pseudo root and always remains false for every other
122     // prim)
123 
124     // Special-case the root (the only prim which has no parent) and
125     // instancing prototypes.
126     if (ARCH_UNLIKELY(!parent || isPrototypePrim)) {
127         _flags[Usd_PrimActiveFlag] = true;
128         _flags[Usd_PrimLoadedFlag] = true;
129         _flags[Usd_PrimModelFlag] = true;
130         _flags[Usd_PrimGroupFlag] = true;
131         _flags[Usd_PrimDefinedFlag] = true;
132         _flags[Usd_PrimHasDefiningSpecifierFlag] = true;
133         _flags[Usd_PrimPrototypeFlag] = isPrototypePrim;
134         _flags[Usd_PrimPseudoRootFlag] = !parent;
135     }
136     else {
137         // Compose and cache 'active'.
138         const bool active = UsdStage::_IsActive(this);
139         _flags[Usd_PrimActiveFlag] = active;
140 
141         // Cache whether or not this prim has a payload.
142         bool hasPayload = _primIndex->HasAnyPayloads();
143         _flags[Usd_PrimHasPayloadFlag] = hasPayload;
144 
145         // An active prim is loaded if it's loadable and in the load set, or
146         // it's not loadable and its parent is loaded.
147         _flags[Usd_PrimLoadedFlag] = active &&
148             (hasPayload ?
149              _stage->_GetPcpCache()->IsPayloadIncluded(_primIndex->GetPath()) :
150              parent->IsLoaded());
151 
152         // According to Model hierarchy rules, only Model Groups may have Model
153         // children (groups or otherwise).  So if our parent is not a Model
154         // Group, then this prim cannot be a model (or a model group).
155         // Otherwise we look up the kind metadata and consult the kind registry.
156         bool isGroup = false, isModel = false;
157         if (parent->IsGroup()) {
158             const TfToken kind = UsdStage::_GetKind(this);
159             // Use the kind registry to determine model/groupness.
160             if (!kind.IsEmpty()) {
161                 isGroup = KindRegistry::IsA(kind, KindTokens->group);
162                 isModel = isGroup || KindRegistry::IsA(kind, KindTokens->model);
163             }
164         }
165         _flags[Usd_PrimGroupFlag] = isGroup;
166         _flags[Usd_PrimModelFlag] = isModel;
167 
168         // Get specifier.
169         const SdfSpecifier specifier = GetSpecifier();
170 
171         // This prim is abstract if its parent is or if it's a class.
172         _flags[Usd_PrimAbstractFlag] =
173             parent->IsAbstract() || specifier == SdfSpecifierClass;
174 
175         // Cache whether or not this prim has an authored defining specifier.
176         const bool isDefiningSpec = SdfIsDefiningSpecifier(specifier);
177         _flags[Usd_PrimHasDefiningSpecifierFlag] = isDefiningSpec;
178 
179         // This prim is defined if its parent is and its specifier is defining.
180         _flags[Usd_PrimDefinedFlag] = isDefiningSpec && parent->IsDefined();
181 
182         // The presence of clips that may affect attributes on this prim
183         // is computed and set in UsdStage. Default to false.
184         _flags[Usd_PrimClipsFlag] = false;
185 
186         // These flags indicate whether this prim is an instance or an
187         // instance prototype.
188         _flags[Usd_PrimInstanceFlag] = active && _primIndex->IsInstanceable();
189         _flags[Usd_PrimPrototypeFlag] = parent->IsInPrototype();
190     }
191 }
192 
193 Usd_PrimDataConstPtr
GetPrimDataAtPathOrInPrototype(const SdfPath & path) const194 Usd_PrimData::GetPrimDataAtPathOrInPrototype(const SdfPath &path) const
195 {
196     return _stage->_GetPrimDataAtPathOrInPrototype(path);
197 }
198 
199 Usd_PrimDataConstPtr
GetPrototype() const200 Usd_PrimData::GetPrototype() const
201 {
202     return _stage->_GetPrototypeForInstance(this);
203 }
204 
205 bool
_ComposePrimChildNames(TfTokenVector * nameOrder)206 Usd_PrimData::_ComposePrimChildNames(TfTokenVector* nameOrder)
207 {
208     // TODO: would be nice to not compute the name order until it is needed
209     // TODO: What do we do with prohibitedNames?
210     PcpTokenSet prohibitedNames;
211     GetSourcePrimIndex().ComputePrimChildNames(nameOrder, &prohibitedNames);
212     return true;
213 }
214 
215 std::string
Usd_DescribePrimData(const Usd_PrimData * p,SdfPath const & proxyPrimPath)216 Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath)
217 {
218     if (!p)
219         return "null prim";
220 
221     bool isInstance = p->IsInstance();
222     bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
223     bool isInPrototype = isInstanceProxy ?
224         Usd_InstanceCache::IsPathInPrototype(proxyPrimPath) :
225         p->IsInPrototype();
226     bool isPrototype = p->IsPrototype();
227     Usd_PrimDataConstPtr prototypeForInstance =
228         isInstance && p->_stage ? p->GetPrototype() : nullptr;
229 
230     return TfStringPrintf(
231         "%s%s%sprim %s<%s> %s%s%s",
232         Usd_IsDead(p) ? "expired " : (p->_flags[Usd_PrimActiveFlag] ?
233                                       "" : "inactive "),
234         p->GetTypeName().IsEmpty() ? "" :
235             TfStringPrintf("'%s' ", p->GetTypeName().GetText()).c_str(),
236         // XXX: Add applied schemas to this descriptor
237         isInstance ? "instance " : isInstanceProxy ? "instance proxy " : "",
238         isInPrototype ? "in prototype " : "",
239         isInstanceProxy ? proxyPrimPath.GetText() : p->_path.GetText(),
240         (isInstanceProxy || isInstance) ? TfStringPrintf(
241             "with prototype <%s> ", isInstance ?
242             prototypeForInstance->GetPath().GetText() :
243             p->_path.GetText()).c_str() : "",
244         (isInstanceProxy || isPrototype || isInPrototype) ? TfStringPrintf(
245             "using prim index <%s> ",
246             p->GetSourcePrimIndex().GetPath().GetText()).c_str() : "",
247         p->_stage ? TfStringPrintf(
248             "on %s", UsdDescribe(p->_stage).c_str()).c_str() : ""
249         );
250 }
251 
252 void
Usd_ThrowExpiredPrimAccessError(const Usd_PrimData * p)253 Usd_ThrowExpiredPrimAccessError(const Usd_PrimData *p)
254 {
255     TF_THROW(UsdExpiredPrimAccessError,
256              TfStringPrintf(
257                  "Used %s", Usd_DescribePrimData(p, SdfPath()).c_str()));
258 }
259 
260 
261 PXR_NAMESPACE_CLOSE_SCOPE
262 
263