From d69f4504a69c4a3cc4e03a9a9054cc7ea09d2a46 Mon Sep 17 00:00:00 2001 From: Mark Tucker Date: Fri, 14 Jan 2022 15:13:33 -0500 Subject: [PATCH 1/2] Adding GetScenePrimPaths method to HdSceneDelegate which allows a single method call to fetch prim paths for a large number of instances in a single method call. Especially useful for native instances which use an O(n) algorithm to discover the path of a single instance. --- pxr/imaging/hd/sceneDelegate.cpp | 8 + pxr/imaging/hd/sceneDelegate.h | 10 ++ pxr/usdImaging/usdImaging/delegate.cpp | 17 +++ pxr/usdImaging/usdImaging/delegate.h | 6 + pxr/usdImaging/usdImaging/instanceAdapter.cpp | 137 ++++++++++++++++++ pxr/usdImaging/usdImaging/instanceAdapter.h | 6 + .../usdImaging/pointInstancerAdapter.cpp | 23 +++ .../usdImaging/pointInstancerAdapter.h | 5 + pxr/usdImaging/usdImaging/primAdapter.cpp | 11 ++ pxr/usdImaging/usdImaging/primAdapter.h | 9 +- 10 files changed, 230 insertions(+), 2 deletions(-) diff --git a/pxr/imaging/hd/sceneDelegate.cpp b/pxr/imaging/hd/sceneDelegate.cpp index 3e2162358f..f64c66e568 100644 --- a/pxr/imaging/hd/sceneDelegate.cpp +++ b/pxr/imaging/hd/sceneDelegate.cpp @@ -304,6 +304,14 @@ HdSceneDelegate::GetScenePrimPath(SdfPath const& rprimId, return rprimId.ReplacePrefix(_delegateID, SdfPath::AbsoluteRootPath()); } +/*virtual*/ +SdfPathVector +HdSceneDelegate::GetScenePrimPaths(SdfPath const& rprimId, + std::vector instanceIndices, + std::vector *instancerContexts) +{ + return SdfPathVector(instanceIndices.size()); +} // -----------------------------------------------------------------------// diff --git a/pxr/imaging/hd/sceneDelegate.h b/pxr/imaging/hd/sceneDelegate.h index b47cbc153f..e3a9be8c2d 100644 --- a/pxr/imaging/hd/sceneDelegate.h +++ b/pxr/imaging/hd/sceneDelegate.h @@ -623,6 +623,16 @@ class HdSceneDelegate { int instanceIndex, HdInstancerContext *instancerContext = nullptr); + /// A vectorized version of GetScenePrimPath that allows the prim adapter + /// to amortize expensive calculations across a number of path evaluations + /// in a single call. Note that only a single rprimId is supported. This + /// allows this call to be forwarded directly to a single prim adapter + /// rather than requiring a lot of data shuffling. + HD_API + virtual SdfPathVector GetScenePrimPaths(SdfPath const& rprimId, + std::vector instanceIndices, + std::vector *instancerContexts = nullptr); + // -----------------------------------------------------------------------// /// \name Material Aspects // -----------------------------------------------------------------------// diff --git a/pxr/usdImaging/usdImaging/delegate.cpp b/pxr/usdImaging/usdImaging/delegate.cpp index bb3da02fa0..51e6ac4c36 100644 --- a/pxr/usdImaging/usdImaging/delegate.cpp +++ b/pxr/usdImaging/usdImaging/delegate.cpp @@ -2254,6 +2254,23 @@ UsdImagingDelegate::GetScenePrimPath(SdfPath const& rprimId, return protoPath; } +SdfPathVector +UsdImagingDelegate::GetScenePrimPaths(SdfPath const& rprimId, + std::vector instanceIndices, + std::vector *instancerContexts) +{ + SdfPath cachePath = ConvertIndexPathToCachePath(rprimId); + _HdPrimInfo *primInfo = _GetHdPrimInfo(cachePath); + if (!primInfo || !primInfo->adapter) { + TF_WARN("GetScenePrimPaths: Couldn't find rprim <%s>", + rprimId.GetText()); + return SdfPathVector(instanceIndices.size(), cachePath); + } + + return primInfo->adapter->GetScenePrimPaths( + cachePath, instanceIndices, instancerContexts); +} + bool UsdImagingDelegate::PopulateSelection( HdSelection::HighlightMode const& highlightMode, diff --git a/pxr/usdImaging/usdImaging/delegate.h b/pxr/usdImaging/usdImaging/delegate.h index ba1211cddc..6a292da0f4 100644 --- a/pxr/usdImaging/usdImaging/delegate.h +++ b/pxr/usdImaging/usdImaging/delegate.h @@ -411,6 +411,12 @@ class UsdImagingDelegate : public HdSceneDelegate, public TfWeakBase { int instanceIndex, HdInstancerContext *instancerContext = nullptr) override; + USDIMAGING_API + virtual SdfPathVector + GetScenePrimPaths(SdfPath const& rprimId, + std::vector instanceIndices, + std::vector *instancerContexts = nullptr) override; + // ExtComputation support USDIMAGING_API TfTokenVector diff --git a/pxr/usdImaging/usdImaging/instanceAdapter.cpp b/pxr/usdImaging/usdImaging/instanceAdapter.cpp index baac40123c..8e7891d674 100644 --- a/pxr/usdImaging/usdImaging/instanceAdapter.cpp +++ b/pxr/usdImaging/usdImaging/instanceAdapter.cpp @@ -2504,6 +2504,143 @@ UsdImagingInstanceAdapter::GetScenePrimPath( return SdfPath(); } +struct UsdImagingInstanceAdapter::_GetScenePrimPathsFn +{ + _GetScenePrimPathsFn( + const UsdImagingInstanceAdapter* adapter_, + const std::vector &instanceIndices_, + const SdfPath &protoPath_) + : adapter(adapter_) + , protoPath(protoPath_) + { + instanceIndices.insert( + instanceIndices_.begin(), instanceIndices_.end()); + } + + void Initialize(size_t numInstances) + { + } + + bool operator()( + const std::vector& instanceContext, size_t instanceIdx) + { + // If this iteration is the right instance index, compose all the USD + // prototype paths together to get the instance proxy path. Include the + // proto path (of the child prim), if one was provided. + if (instanceIndices.find(instanceIdx) != instanceIndices.end()) { + SdfPathVector instanceChain; + // To get the correct prim-in-prototype, we need to add the + // prototype path to the instance chain. However, there's a case in + // _Populate where we populate prims that are just a USD prototype + // (used by e.g. cards). In this case, the hydra proto path is + // overridden to be the path of the USD instance, and we don't want + // to add it to the instance chain since instanceContext.front + // would duplicate it. + UsdPrim p = adapter->_GetPrim(protoPath); + if (p && !p.IsInstance()) { + instanceChain.push_back(protoPath); + } + for (UsdPrim const& prim : instanceContext) { + instanceChain.push_back(prim.GetPath()); + } + primPaths.emplace(instanceIdx, + adapter->_GetPrimPathFromInstancerChain(instanceChain)); + // We can stop iterating when we've found a prim path for each + // instance index. + return primPaths.size() != instanceIndices.size(); + } + return true; + } + + const UsdImagingInstanceAdapter* adapter; + const SdfPath& protoPath; + std::set instanceIndices; + std::map primPaths; +}; + +/* virtual */ +SdfPathVector +UsdImagingInstanceAdapter::GetScenePrimPaths( + SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const +{ + HD_TRACE_FUNCTION(); + + // For child prims (hydra prototypes) and USD instances, the process is + // the same: find the associated hydra instancer, and use the instance + // index to look up the composed instance path. They differ based on + // whether you append a hydra proto path, and how you find the + // hydra instancer. + UsdPrim usdPrim = _GetPrim(cachePath.GetAbsoluteRootOrPrimPath()); + if (_IsChildPrim(usdPrim, cachePath)) { + + TF_DEBUG(USDIMAGING_SELECTION).Msg( + "GetScenePrimPaths: instance proto = %s\n", cachePath.GetText()); + + UsdImagingInstancerContext instancerContext; + _ProtoPrim const& proto = _GetProtoPrim( + cachePath.GetAbsoluteRootOrPrimPath(), + cachePath, &instancerContext); + + if (!proto.adapter) { + return SdfPathVector(instanceIndices.size(), cachePath); + } + + _InstancerData const* instrData = + TfMapLookupPtr(_instancerData, instancerContext.instancerCachePath); + if (!instrData) { + return SdfPathVector(instanceIndices.size(), cachePath); + } + + UsdPrim instancerPrim = _GetPrim(instancerContext.instancerCachePath); + + // Translate from hydra instance index to USD (since hydra filters out + // invisible instances). + VtIntArray indices = _ComputeInstanceMap(instancerPrim, *instrData, + _GetTimeWithOffset(0.0)); + std::vector remappedIndices; + + remappedIndices.reserve(instanceIndices.size()); + for (size_t i = 0; i < instanceIndices.size(); i++) + remappedIndices.push_back(indices[instanceIndices[i]]); + + SdfPathVector result; + result.reserve(instanceIndices.size()); + _GetScenePrimPathsFn primPathsFn(this, remappedIndices, proto.path); + _RunForAllInstancesToDraw(instancerPrim, &primPathsFn); + for (size_t i = 0; i < remappedIndices.size(); i++) + result.push_back(primPathsFn.primPaths[remappedIndices[i]]); + return result; + } else { + + TF_DEBUG(USDIMAGING_SELECTION).Msg( + "GetScenePrimPaths: instance = %s\n", cachePath.GetText()); + + SdfPath const* instancerPath = + TfMapLookupPtr(_instanceToInstancerMap, cachePath); + if (instancerPath == nullptr) { + return SdfPathVector(instanceIndices.size(), cachePath); + } + _InstancerData const* instrData = + TfMapLookupPtr(_instancerData, *instancerPath); + if (instrData == nullptr) { + return SdfPathVector(instanceIndices.size(), cachePath); + } + + SdfPathVector result; + result.reserve(instanceIndices.size()); + _GetScenePrimPathsFn primPathsFn(this, instanceIndices, + SdfPath::EmptyPath()); + _RunForAllInstancesToDraw(_GetPrim(*instancerPath), &primPathsFn); + for (size_t i = 0; i < instanceIndices.size(); i++) + result.push_back(primPathsFn.primPaths[instanceIndices[i]]); + return result; + } + + return SdfPathVector(instanceIndices.size(), cachePath); +} + struct UsdImagingInstanceAdapter::_PopulateInstanceSelectionFn { _PopulateInstanceSelectionFn( diff --git a/pxr/usdImaging/usdImaging/instanceAdapter.h b/pxr/usdImaging/usdImaging/instanceAdapter.h index e76775296a..8a154c1d49 100644 --- a/pxr/usdImaging/usdImaging/instanceAdapter.h +++ b/pxr/usdImaging/usdImaging/instanceAdapter.h @@ -314,6 +314,11 @@ class UsdImagingInstanceAdapter : public UsdImagingPrimAdapter int instanceIndex, HdInstancerContext *instancerContext) const override; + virtual SdfPathVector GetScenePrimPaths( + SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const override; + virtual bool PopulateSelection( HdSelection::HighlightMode const& highlightMode, SdfPath const &cachePath, @@ -455,6 +460,7 @@ class UsdImagingInstanceAdapter : public UsdImagingPrimAdapter struct _PopulateInstanceSelectionFn; struct _GetScenePrimPathFn; + struct _GetScenePrimPathsFn; // Helper functions for dealing with "actual" instances to be drawn. // diff --git a/pxr/usdImaging/usdImaging/pointInstancerAdapter.cpp b/pxr/usdImaging/usdImaging/pointInstancerAdapter.cpp index 49c6e7fbca..13391c58b1 100644 --- a/pxr/usdImaging/usdImaging/pointInstancerAdapter.cpp +++ b/pxr/usdImaging/usdImaging/pointInstancerAdapter.cpp @@ -1359,6 +1359,29 @@ UsdImagingPointInstancerAdapter::GetScenePrimPath( return _GetPrimPathFromInstancerChain(paths); } +/* virtual */ +SdfPathVector +UsdImagingPointInstancerAdapter::GetScenePrimPaths( + SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const +{ + SdfPathVector result; + HdInstancerContext instanceCtx; + + result.reserve(instanceIndices.size()); + if (instancerCtxs) + instancerCtxs->reserve(instanceIndices.size()); + for (size_t i = 0; i < instanceIndices.size(); i++) { + result.push_back( + GetScenePrimPath(cachePath, instanceIndices[i], &instanceCtx)); + if (instancerCtxs) + instancerCtxs->push_back(std::move(instanceCtx)); + } + + return result; +} + static size_t _GatherAuthoredTransformTimeSamples( diff --git a/pxr/usdImaging/usdImaging/pointInstancerAdapter.h b/pxr/usdImaging/usdImaging/pointInstancerAdapter.h index 573071fea3..f7f254fd35 100644 --- a/pxr/usdImaging/usdImaging/pointInstancerAdapter.h +++ b/pxr/usdImaging/usdImaging/pointInstancerAdapter.h @@ -260,6 +260,11 @@ class UsdImagingPointInstancerAdapter : public UsdImagingPrimAdapter int instanceIndex, HdInstancerContext *instancerContext) const override; + virtual SdfPathVector GetScenePrimPaths( + SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const override; + virtual bool PopulateSelection( HdSelection::HighlightMode const& highlightMode, SdfPath const &cachePath, diff --git a/pxr/usdImaging/usdImaging/primAdapter.cpp b/pxr/usdImaging/usdImaging/primAdapter.cpp index 8eb0984b7c..1fc2157d58 100644 --- a/pxr/usdImaging/usdImaging/primAdapter.cpp +++ b/pxr/usdImaging/usdImaging/primAdapter.cpp @@ -478,6 +478,17 @@ UsdImagingPrimAdapter::GetScenePrimPath( return cachePath; } +/*virtual*/ +SdfPathVector +UsdImagingPrimAdapter::GetScenePrimPaths(SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const +{ + // Note: if we end up here, we're not instanced, since primInfo + // holds the instance adapter for instanced gprims. + return SdfPathVector(instanceIndices.size(), cachePath); +} + /*virtual*/ bool UsdImagingPrimAdapter::PopulateSelection( diff --git a/pxr/usdImaging/usdImaging/primAdapter.h b/pxr/usdImaging/usdImaging/primAdapter.h index 4480942142..9869db0165 100644 --- a/pxr/usdImaging/usdImaging/primAdapter.h +++ b/pxr/usdImaging/usdImaging/primAdapter.h @@ -344,8 +344,13 @@ class UsdImagingPrimAdapter USDIMAGING_API virtual SdfPath GetScenePrimPath(SdfPath const& cachePath, - int instanceIndex, - HdInstancerContext *instancerCtx) const; + int instanceIndex, + HdInstancerContext *instancerCtx) const; + + USDIMAGING_API + virtual SdfPathVector GetScenePrimPaths(SdfPath const& cachePath, + std::vector const& instanceIndices, + std::vector *instancerCtxs) const; // Add the given usdPrim to the HdSelection object, to mark it for // selection highlighting. cachePath is the path of the object referencing From 6cff42305a5c7790eef2ffa7581fdfc47d28b0d8 Mon Sep 17 00:00:00 2001 From: Mark Tucker Date: Thu, 10 Mar 2022 16:43:30 -0500 Subject: [PATCH 2/2] Re-implement UsdImagingInstancerAdapter::GetScenePrimPath in terms of GetScenePrimPaths, to eliminate a large amount of nearly-duplicated code. --- pxr/usdImaging/usdImaging/instanceAdapter.cpp | 114 +----------------- 1 file changed, 5 insertions(+), 109 deletions(-) diff --git a/pxr/usdImaging/usdImaging/instanceAdapter.cpp b/pxr/usdImaging/usdImaging/instanceAdapter.cpp index 8e7891d674..dea0df0ddb 100644 --- a/pxr/usdImaging/usdImaging/instanceAdapter.cpp +++ b/pxr/usdImaging/usdImaging/instanceAdapter.cpp @@ -2384,55 +2384,6 @@ UsdImagingInstanceAdapter::_ComputeInstanceMap( return indices; } -struct UsdImagingInstanceAdapter::_GetScenePrimPathFn -{ - _GetScenePrimPathFn( - const UsdImagingInstanceAdapter* adapter_, - int instanceIndex_, - const SdfPath &protoPath_) - : adapter(adapter_) - , instanceIndex(instanceIndex_) - , protoPath(protoPath_) - { } - - void Initialize(size_t numInstances) - { - } - - bool operator()( - const std::vector& instanceContext, size_t instanceIdx) - { - // If this iteration is the right instance index, compose all the USD - // prototype paths together to get the instance proxy path. Include the - // proto path (of the child prim), if one was provided. - if (instanceIdx == instanceIndex) { - SdfPathVector instanceChain; - // To get the correct prim-in-prototype, we need to add the - // prototype path to the instance chain. However, there's a case in - // _Populate where we populate prims that are just a USD prototype - // (used by e.g. cards). In this case, the hydra proto path is - // overridden to be the path of the USD instance, and we don't want - // to add it to the instance chain since instanceContext.front - // would duplicate it. - UsdPrim p = adapter->_GetPrim(protoPath); - if (p && !p.IsInstance()) { - instanceChain.push_back(protoPath); - } - for (UsdPrim const& prim : instanceContext) { - instanceChain.push_back(prim.GetPath()); - } - primPath = adapter->_GetPrimPathFromInstancerChain(instanceChain); - return false; - } - return true; - } - - const UsdImagingInstanceAdapter* adapter; - const size_t instanceIndex; - const SdfPath& protoPath; - SdfPath primPath; -}; - /* virtual */ SdfPath UsdImagingInstanceAdapter::GetScenePrimPath( @@ -2442,66 +2393,11 @@ UsdImagingInstanceAdapter::GetScenePrimPath( { HD_TRACE_FUNCTION(); - // For child prims (hydra prototypes) and USD instances, the process is - // the same: find the associated hydra instancer, and use the instance - // index to look up the composed instance path. They differ based on - // whether you append a hydra proto path, and how you find the - // hydra instancer. - UsdPrim usdPrim = _GetPrim(cachePath.GetAbsoluteRootOrPrimPath()); - if (_IsChildPrim(usdPrim, cachePath)) { - - TF_DEBUG(USDIMAGING_SELECTION).Msg( - "GetScenePrimPath: instance proto = %s\n", cachePath.GetText()); - - UsdImagingInstancerContext instancerContext; - _ProtoPrim const& proto = _GetProtoPrim( - cachePath.GetAbsoluteRootOrPrimPath(), - cachePath, &instancerContext); - - if (!proto.adapter) { - return SdfPath(); - } - - _InstancerData const* instrData = - TfMapLookupPtr(_instancerData, instancerContext.instancerCachePath); - if (!instrData) { - return SdfPath(); - } - - UsdPrim instancerPrim = _GetPrim(instancerContext.instancerCachePath); - - // Translate from hydra instance index to USD (since hydra filters out - // invisible instances). - VtIntArray indices = _ComputeInstanceMap(instancerPrim, *instrData, - _GetTimeWithOffset(0.0)); - - instanceIndex = indices[instanceIndex]; - - _GetScenePrimPathFn primPathFn(this, instanceIndex, proto.path); - _RunForAllInstancesToDraw(instancerPrim, &primPathFn); - return primPathFn.primPath; - } else { - - TF_DEBUG(USDIMAGING_SELECTION).Msg( - "GetScenePrimPath: instance = %s\n", cachePath.GetText()); - - SdfPath const* instancerPath = - TfMapLookupPtr(_instanceToInstancerMap, cachePath); - if (instancerPath == nullptr) { - return SdfPath(); - } - _InstancerData const* instrData = - TfMapLookupPtr(_instancerData, *instancerPath); - if (instrData == nullptr) { - return SdfPath(); - } - _GetScenePrimPathFn primPathFn(this, instanceIndex, - SdfPath::EmptyPath()); - _RunForAllInstancesToDraw(_GetPrim(*instancerPath), &primPathFn); - return primPathFn.primPath; - } - - return SdfPath(); + // Pass nullptr to instancerCtxs because this value is never used by + // our implementation of this method. + SdfPathVector paths = GetScenePrimPaths( + cachePath, { instanceIndex }, nullptr); + return paths.size() > 0 ? paths[0] : SdfPath(); } struct UsdImagingInstanceAdapter::_GetScenePrimPathsFn