Autodesk / Autodesk/maya-usd

Poor Hydra Performance When Changing the Transform of an Asset

Open
#4,395 10 comments 0 reactions 1 assignee Claimed by @santosd View on GitHub
Dominant language
Wolfram Language
Stars
905
Forks
223
Avg merge
2d 9h
Merged PRs (30d)
17

Description

Hello,

We have an asset consisting of about 1500 prims and is constructed out of pieces via payloads. USD instancing is enabled on the prims with the payloads. The asset is placed in a scene as a payload as well. We noticed that manipulating the asset's transform is slow when there are multiple instances of the asset. I have profiled with USD trace events and Windows Performance Analyzer and found several areas that are slow. Some areas are in USD Hydra and others are in the MayaUsd VP2 render delegate. The performance degrades with the number of instances of the asset even though only a single instance is being manipulated.

We can't provide the real asset so I made a tower of 1600 cubes and placed 125 instances of the tower in a scene. One version of the tower is just 1600 cubes with no referencing. In the second version I created a hierarchy of references, analogous to how we construct our assets: Cube.usda is the leaf, then Row.usda is a row 8 cube references, Floor.usda is 8 row references, and TowerOfCubes_HierarchyRefs.usda is 25 floor references.

I'm going to only point out performance problems in MayaUsd here.

For the tower of cubes that doesn't have a hierarchy of references, it takes about 110ms in total to translate the tower in Maya. Not great for an interactive editing experience. For the hierarchy of references, it takes about 3.5 seconds to move! The biggest culprit is "_SyncDisplayLayerModesInstanced", taking alomst 2 seconds in the referenced case. This function is gathering all the USD prim paths from the scene to determine if they are part of a display layer so the rendering can change for the Hydra prim. I think this can be fixed by: 1) Use a display layer dirty flag to do this processing only when the state of a display layer changes, right now it's called no matter what 2) Invert the lookup so the iteration is over the display layers to get the USD path, then get the corresponding Hydra prim to change the rendering for. I'm not sure if this inverse mapping from USD to Hydra prim is available.

Another slow part is "HdVP2RenderDelegate::CommitResources". This takes ~61ms in the non-referenced case and ~33ms in the referenced case. I haven't dug into this code yet.

The last thing that stuck out to me was "HdVP2Mesh::_UpdateDrawItem" in the non-referenced case. It's being called 4800 times when there are 1600 cubes, or two additional times. My guess is that one of the extra calls is because it's selected and I wonder if it's doing duplicate work that could be cached somehow. I don't know what the third extra call is for but it looks to take very little time. Commenting out the call to "_SyncDisplayLayerModesInstanced" still results in a slow "_UpdateDrawItem" call compared to UsdView, for example, comparing the most expensive call between the two is ~7ms for MayaUsd vs. ~388 microseconds for UsdView. The time per call is much higher and it's being called more often.

Ideally, when changing the transform there should be minimal work done and happen at interactive framerates. For example in a game engine, the entire game is typically simulated and rendered in ~16.7ms (60fps) or ~33ms (30fps).

I'm going to attempt to optimize the areas I presented, starting with "_SyncDisplayLayerModesInstanced", but I don't know how well that is going to go since I am not an expert. Is there already on-going work or planned work to optimize MayaUsd rendering?

I have attached a zip file containing:
- Scene folder:
- ProfileMoveMaya.py: A python script to record the trace of moving an object in Maya. I execute this script in the Maya ScriptEditor, select a tower, and then call the profile_move function.
- ProfileMoveUsdView.py: A python script to record the trace of moving an object in UsdView. Call the "profile_move" function first, wait the for the move to happen, then call the "stop_trace" function.
- StressTest.usda: 125 references of towers of cubes without hierarchical referencing.
- StressTest_HierarchyRefs: 125 references of towers with hierarchical referencing.
- TowerOfCubes.usda: 1600 cubes
- TowerOfCubes_HierarchyRefs.usda: References Floor.usda 25 times.
- Floor.usda: References Row.usda 8 times.
- Row.usda: References Cube.usda 8 times.
- GenerateStressTest.py: This generates the .usda files without hierarchical referencing if no argument is given. The "--hierarchy-refs" argument will generate hierarchical references.
- Traces folder:
- StressTest_Maya.json: Trace Event profile of 125 tower of cubes in Maya without hierarchical referencing.
- StressTest_UsdView.json: Trace Event profile of 125 tower of cubes in UsdView without hierarchical referencing.
- StressTestHierarchyRefs_Maya.json: Trace Event profile of 125 tower of cubes in Maya with hierarchical referencing.
- StressTestHierarchyRefs_UsdView.json: Trace Event profile of 125 tower of cubes in UsdView with hierarchical referencing.

Notes:

MayaUsd version 0.33.0
OpenUsd version 25.08

There is overhead due to tracing.

I have commented out some TRACE_FUNCTION() calls to significantly reduce the trace sizes:
- pxr\usd\sdf\path.cpp, SdfPath::ReplacePrefix, line 1411
- pxr\usdImaging\usdImaging\instanceAdapter.cpp, UsdImagingInstanceAdapter::IsChildPath, line 1883
- pxr\usdImaging\usdImaging\primAdapter.cpp, UsdImagingPrimAdapter::GetTransform, line 1267
- pxr\usdImaging\usdImaging\resolvedAttributeCache.h, GetValue, line 94

I have also added some trace calls:
- pxr\usdImaging\usdImaging\delegate.cpp line 1651: { HD_TRACE_SCOPE("AffectedCachePaths"); ... }
- lib\mayaUsd\render\vp2RenderDelegate\mayaPrimCommon.cpp, MayaUsdRPrim::_SyncDisplayLayerModesInstanced, line 842: HD_TRACE_FUNCTION();
- lib\mayaUsd\render\vp2RenderDelegate\mesh.cpp, HdVP2Mesh::Sync, line 819: HD_TRACE_FUNCTION();
- lib\mayaUsd\render\vp2RenderDelegate\mesh.cpp, HdVP2Mesh::_UpdateRepr, line 1484: HD_TRACE_FUNCTION();
- lib\mayaUsd\render\vp2RenderDelegate\mesh.cpp, HdVP2Mesh::_UpdateDrawItem, line 1608: HD_TRACE_FUNCTION();
- lib\mayaUsd\render\vp2RenderDelegate\renderDelegate.cpp, HdVP2RenderDelegate::CommitResources, line 708: HD_TRACE_FUNCTION();

[PoorMayaUsdHydraPerformance.zip](https://github.com/user-attachments/files/23966560/PoorMayaUsdHydraPerformance.zip)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.