Skip to content

Commit

Permalink
Adding UsdResolveTarget which can be used to perform attribute value
Browse files Browse the repository at this point in the history
resolution using only a subrange of a prim's prim stack.

A UsdResolveTarget holds a prim index and iterator ranges determining
the start node and layer and stop node and layer that a Usd_Resolver
should use when iterating over a prim index for value resolution.

UsdResolveTargets can only be consumed by UsdAttributeQuery(s) during
construction. Proving an attribute query will limit value resolution for
all its methods to the prim stack subrange of the resolve target.

UsdResolverTargets can only be created by the following methods
  UsdPrimCompositionQueryArc::MakeResolveTargetUpTo
  UsdPrimCompositionQueryArc::MakeResolveTargetStrongerThan
  UsdPrim::MakeResolveTargetUpToEditTarget
  UsdPrim::MakeResolveTargetStrongerThanEditTarget
The query arc methods produce resolve targets that limit value
resolution to either "up to" or "stronger than" that particular
composition arc. The UsdPrim methods produce resolve targets that limit
value resolution to "up to" or "stronger than" the spec that would be
authored by a given UsdEditTarget for the prim.

Fixes #1483

(Internal change: 2250352)
  • Loading branch information
pixar-oss committed Sep 28, 2022
1 parent 8e94cbc commit 52800ba
Show file tree
Hide file tree
Showing 26 changed files with 2,051 additions and 60 deletions.
35 changes: 35 additions & 0 deletions pxr/usd/usd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pxr_library(usd
references
relationship
resolveInfo
resolveTarget
resolver
schemaBase
schemaRegistry
Expand Down Expand Up @@ -132,6 +133,7 @@ pxr_library(usd
wrapReferences.cpp
wrapRelationship.cpp
wrapResolveInfo.cpp
wrapResolveTarget.cpp
wrapSchemaBase.cpp
wrapSchemaRegistry.cpp
wrapSpecializes.cpp
Expand Down Expand Up @@ -234,6 +236,7 @@ pxr_test_scripts(
testenv/testUsdPrims.py
testenv/testUsdReferences.py
testenv/testUsdRelationships.py
testenv/testUsdResolveTargetPy.py
testenv/testUsdSchemaBasePy.py
testenv/testUsdSchemaRegistry.py
testenv/testUsdSpecializes.py
Expand Down Expand Up @@ -407,6 +410,17 @@ pxr_build_test(testUsdSchemaBase
testenv/testUsdSchemaBase.cpp
)

pxr_build_test(testUsdResolveTarget
LIBRARIES
pcp
sdf
tf
usd
vt
CPPFILES
testenv/testUsdResolveTarget.cpp
)

pxr_build_test(testUsdTimeValueAuthoringCpp
LIBRARIES
arch
Expand Down Expand Up @@ -538,6 +552,16 @@ pxr_install_test_dir(
DEST testUsdResolverChanged
)

pxr_install_test_dir(
SRC testenv/testUsdResolveTarget.testenv
DEST testUsdResolveTarget
)

pxr_install_test_dir(
SRC testenv/testUsdResolveTarget.testenv
DEST testUsdResolveTargetPy
)

pxr_install_test_dir(
SRC testenv/testUsdNotices.testenv
DEST testUsdNotices
Expand Down Expand Up @@ -1002,6 +1026,17 @@ pxr_register_test(testUsdModel
EXPECTED_RETURN_CODE 0
)

pxr_register_test(testUsdResolveTarget
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdResolveTarget"
EXPECTED_RETURN_CODE 0
)

pxr_register_test(testUsdResolveTargetPy
PYTHON
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdResolveTargetPy"
EXPECTED_RETURN_CODE 0
)

pxr_register_test(testUsdSpecializes
PYTHON
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdSpecializes"
Expand Down
61 changes: 52 additions & 9 deletions pxr/usd/usd/attributeQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ PXR_NAMESPACE_OPEN_SCOPE


UsdAttributeQuery::UsdAttributeQuery(
const UsdAttribute& attr)
const UsdAttribute& attr) :
_attr(attr)
{
_Initialize(attr);
_Initialize();
}

UsdAttributeQuery::UsdAttributeQuery(
Expand All @@ -47,6 +48,14 @@ UsdAttributeQuery::UsdAttributeQuery(
{
}

UsdAttributeQuery::UsdAttributeQuery(
const UsdAttribute &attr,
const UsdResolveTarget &resolveTarget) :
_attr(attr)
{
_Initialize(resolveTarget);
}

std::vector<UsdAttributeQuery>
UsdAttributeQuery::CreateQueries(
const UsdPrim& prim, const TfTokenVector& attrNames)
Expand All @@ -65,16 +74,45 @@ UsdAttributeQuery::UsdAttributeQuery()
}

void
UsdAttributeQuery::_Initialize(const UsdAttribute& attr)
UsdAttributeQuery::_Initialize()
{
TRACE_FUNCTION();

if (attr) {
const UsdStage* stage = attr._GetStage();
stage->_GetResolveInfo(attr, &_resolveInfo);
if (_attr) {
const UsdStage* stage = _attr._GetStage();
stage->_GetResolveInfo(_attr, &_resolveInfo);
}
}

void
UsdAttributeQuery::_Initialize(
const UsdResolveTarget &resolveTarget)
{
TRACE_FUNCTION();

if (resolveTarget.IsNull()) {
_Initialize();
return;
}

if (!_attr) {
return;
}

// Validate that the resolve target is for this attribute's prim path.
if (_attr.GetPrimPath() != resolveTarget.GetPrimIndex()->GetPath()) {
TF_CODING_ERROR("Invalid resolve target for attribute '%s'. The "
"given resolve target is only valid for attributes on the prim "
"'%s'.",
_attr.GetPrimPath().GetText(),
resolveTarget.GetPrimIndex()->GetPath().GetText());
return;
}

const UsdStage* stage = _attr._GetStage();
stage->_GetResolveInfoWithResolveTarget(_attr, resolveTarget, &_resolveInfo);

_attr = attr;
_resolveTarget = resolveTarget;
}

const UsdAttribute&
Expand All @@ -98,8 +136,13 @@ UsdAttributeQuery::_Get(T* value, UsdTimeCode time) const

static const UsdTimeCode defaultTime = UsdTimeCode::Default();
UsdResolveInfo defaultResolveInfo;
_attr._GetStage()->_GetResolveInfo(
_attr, &defaultResolveInfo, &defaultTime);
if (_resolveTarget.IsNull()) {
_attr._GetStage()->_GetResolveInfo(
_attr, &defaultResolveInfo, &defaultTime);
} else {
_attr._GetStage()->_GetResolveInfoWithResolveTarget(
_attr, _resolveTarget, &defaultResolveInfo, &defaultTime);
}
return _attr._GetStage()->_GetValueFromResolveInfo(
defaultResolveInfo, defaultTime, _attr, value);
}
Expand Down
26 changes: 24 additions & 2 deletions pxr/usd/usd/attributeQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "pxr/usd/usd/common.h"
#include "pxr/usd/usd/prim.h"
#include "pxr/usd/usd/resolveInfo.h"
#include "pxr/usd/usd/resolveTarget.h"
#include "pxr/usd/usd/timeCode.h"

#include "pxr/base/tf/token.h"
Expand All @@ -52,7 +53,16 @@ PXR_NAMESPACE_OPEN_SCOPE
/// the attribute \em is affected by Value Clips, the performance gain will
/// just be less.
///
/// \section Thread safety
/// \section Resolve_targets Resolve targets
/// An attribute query can also be constructed for an attribute along with a
/// UsdResolveTarget. A resolve target allows value resolution to consider only
/// a subrange of the prim stack instead of the entirety of it. All of the methods
/// of an attribute query created with a resolve target will perform value
/// resolution within that resolve target. This can be useful for finding the
/// value of an attribute resolved up to a particular layer or for determining
/// if a value authored on layer would be overridden by a stronger opinion.
///
/// \section Thread_safety Thread safety
/// This object provides the basic thread-safety guarantee. Multiple threads
/// may call the value accessor functions simultaneously.
///
Expand All @@ -79,6 +89,15 @@ class UsdAttributeQuery
USD_API
UsdAttributeQuery(const UsdPrim& prim, const TfToken& attrName);

/// Construct a new query for the attribute \p attr with the given
/// resolve target \p resolveTarget.
///
/// Note that a UsdResolveTarget is associated with a particular prim so
/// only resolve targets for the attribute's owning prim are allowed.
USD_API
UsdAttributeQuery(const UsdAttribute &attr,
const UsdResolveTarget &resolveTarget);

/// Construct new queries for the attributes named in \p attrNames under
/// the prim \p prim. The objects in the returned vector will line up
/// 1-to-1 with \p attrNames.
Expand Down Expand Up @@ -242,7 +261,9 @@ class UsdAttributeQuery
/// @}

private:
void _Initialize(const UsdAttribute& attr);
void _Initialize();

void _Initialize(const UsdResolveTarget &resolveTarget);

template <typename T>
USD_API
Expand All @@ -251,6 +272,7 @@ class UsdAttributeQuery
private:
UsdAttribute _attr;
UsdResolveInfo _resolveInfo;
UsdResolveTarget _resolveTarget;
};

PXR_NAMESPACE_CLOSE_SCOPE
Expand Down
1 change: 1 addition & 0 deletions pxr/usd/usd/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ TF_WRAP_MODULE
TF_WRAP(UsdPrimFlags);
TF_WRAP(UsdPrimTypeInfo);
TF_WRAP(UsdReferences);
TF_WRAP(UsdResolveTarget);
TF_WRAP(UsdSchemaRegistry);
TF_WRAP(UsdSpecializes);
TF_WRAP(UsdPrimRange);
Expand Down
82 changes: 82 additions & 0 deletions pxr/usd/usd/prim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
#include "pxr/usd/usd/prim.h"

#include "pxr/usd/usd/apiSchemaBase.h"
#include "pxr/usd/usd/editTarget.h"
#include "pxr/usd/usd/inherits.h"
#include "pxr/usd/usd/instanceCache.h"
#include "pxr/usd/usd/payloads.h"
#include "pxr/usd/usd/primRange.h"
#include "pxr/usd/usd/relationship.h"
#include "pxr/usd/usd/references.h"
#include "pxr/usd/usd/resolver.h"
#include "pxr/usd/usd/resolveTarget.h"
#include "pxr/usd/usd/schemaBase.h"
#include "pxr/usd/usd/schemaRegistry.h"
#include "pxr/usd/usd/specializes.h"
Expand Down Expand Up @@ -1446,6 +1448,86 @@ UsdPrim::ComputeExpandedPrimIndex() const
return outputs.primIndex;
}

static PcpNodeRef
_FindStrongestNodeMatchingEditTarget(
const PcpPrimIndex& index, const UsdEditTarget &editTarget)
{
// Use the edit target to map the prim's path to the path we expect to find
// a node for.
const SdfPath &rootPath = index.GetRootNode().GetPath();
const SdfPath mappedPath = editTarget.MapToSpecPath(rootPath);

if (mappedPath.IsEmpty()) {
return PcpNodeRef();
}

// We're looking for the first (strongest) node that would be affected by
// an edit to the prim using the edit target which means we are looking for
// the following criteria to be met:
// 1. The node's path matches the prim path mapped through the edit target.
// 2. The edit target's layer is in the node's layer stack.
for (const PcpNodeRef &node : index.GetNodeRange()) {
if (node.GetPath() != mappedPath) {
continue;
}

if (node.GetLayerStack()->HasLayer(editTarget.GetLayer())) {
return node;
}
}

return PcpNodeRef();
}

UsdResolveTarget
UsdPrim::_MakeResolveTargetFromEditTarget(
const UsdEditTarget &editTarget,
bool makeAsStrongerThan) const
{
// Need the expanded prim index to find nodes and layers that may have been
// culled out in the cached prim index.
PcpPrimIndex expandedPrimIndex = ComputeExpandedPrimIndex();
if (!expandedPrimIndex.IsValid()) {
return UsdResolveTarget();
}

const PcpNodeRef node = _FindStrongestNodeMatchingEditTarget(
expandedPrimIndex, editTarget);
if (!node) {
return UsdResolveTarget();
}

// The resolve target needs to hold on to the expanded prim index.
std::shared_ptr<PcpPrimIndex> resolveIndex =
std::make_shared<PcpPrimIndex>(std::move(expandedPrimIndex));

if (makeAsStrongerThan) {
// Return a resolve target starting at the root node and stopping at the
// edit node and layer.
return UsdResolveTarget(resolveIndex,
node.GetRootNode(), nullptr, node, editTarget.GetLayer());
} else {
// Return a resolve target starting at the edit node and layer.
return UsdResolveTarget(resolveIndex, node, editTarget.GetLayer());
}
}

UsdResolveTarget
UsdPrim::MakeResolveTargetUpToEditTarget(
const UsdEditTarget &editTarget) const
{
return _MakeResolveTargetFromEditTarget(
editTarget, /* makeAsStrongerThan = */ false);
}

UsdResolveTarget
UsdPrim::MakeResolveTargetStrongerThanEditTarget(
const UsdEditTarget &editTarget) const
{
return _MakeResolveTargetFromEditTarget(
editTarget, /* makeAsStrongerThan = */ true);
}

UsdPrim
UsdPrim::GetPrimAtPath(const SdfPath& path) const{
const SdfPath absolutePath = path.MakeAbsolutePath(GetPath());
Expand Down
31 changes: 31 additions & 0 deletions pxr/usd/usd/prim.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ class UsdPrimRange;
class Usd_PrimData;

class UsdAttribute;
class UsdEditTarget;
class UsdRelationship;
class UsdPayloads;
class UsdReferences;
class UsdResolveTarget;
class UsdSchemaBase;
class UsdAPISchemaBase;
class UsdInherits;
Expand Down Expand Up @@ -1671,6 +1673,28 @@ class UsdPrim : public UsdObject
USD_API
PcpPrimIndex ComputeExpandedPrimIndex() const;

/// Creates and returns a resolve target that, when passed to a
/// UsdAttributeQuery for one of this prim's attributes, causes value
/// resolution to only consider weaker specs up to and including the spec
/// that would be authored for this prim when using the given \p editTarget.
///
/// If the edit target would not affect any specs that could contribute to
/// this prim, a null resolve target is returned.
USD_API
UsdResolveTarget MakeResolveTargetUpToEditTarget(
const UsdEditTarget &editTarget) const;

/// Creates and returns a resolve target that, when passed to a
/// UsdAttributeQuery for one of this prim's attributes, causes value
/// resolution to only consider specs that are stronger than the spec
/// that would be authored for this prim when using the given \p editTarget.
///
/// If the edit target would not affect any specs that could contribute to
/// this prim, a null resolve target is returned.
USD_API
UsdResolveTarget MakeResolveTargetStrongerThanEditTarget(
const UsdEditTarget &editTarget) const;

/// @}

private:
Expand Down Expand Up @@ -1742,6 +1766,13 @@ class UsdPrim : public UsdObject
// for testing and debugging purposes.
const PcpPrimIndex &_GetSourcePrimIndex() const
{ return _Prim()->GetSourcePrimIndex(); }

// Helper function for MakeResolveTargetUpToEditTarget and
// MakeResolveTargetStrongerThanEditTarget.
UsdResolveTarget
_MakeResolveTargetFromEditTarget(
const UsdEditTarget &editTarget,
bool makeAsStrongerThan) const;
};

#ifdef doxygen
Expand Down
Loading

0 comments on commit 52800ba

Please sign in to comment.