I’m working on a USD-based renderer, and I’ve built a cloud asset system that progressively downloads different LODs for assets. The same asset reference in a scene resolves to different files on disk as higher-quality LODs finish downloading.
For example, a reference to “cloud://building_01” might initially resolve to a low-poly proxy that’s already cached locally. As the session continues, the system downloads medium and then high-res versions in the background. When a new LOD arrives on disk, I need the stage to re-resolve that asset path to the new file and, critically, I need Hydra to pick up the change and re-sync the affected prims so the renderer displays the updated geometry.
What I’ve tried:
ArNotice::ResolverChanged().Send() — This seems to invalidate the resolution cache, but it doesn’t trigger recomposition in a way that Hydra observes. The scene delegate doesn’t respond to resolver-level notices, so the render delegate never gets dirty prims to re-sync.
SdfLayer::Reload() on affected layers — Similar issue. Even when the stage recomposes, Hydra doesn’t always pick up the changes.
What actually works:
The only reliable method I’ve found is calling UsdUtilsModifyAssetPaths twice — effectively touching the asset path specs so that real SdfChangeList entries are generated. This propagates through the full change processing pipeline and Hydra correctly dirties and re-syncs the affected prims with the new LOD.
While this works, it feels heavy. For a progressive download system where assets may update frequently as LODs stream in, rewriting all asset paths just to generate change notices is more expensive than it should be.
My questions:
Is there a recommended way to signal that the file backing a resolved asset path has changed and have that propagate all the way through to Hydra?
Should ArNotice::ResolverChanged be expected to trigger Hydra updates? If not, is there a planned mechanism for this kind of dynamic re-resolution?
Is there a lighter-weight approach than UsdUtilsModifyAssetPaths to generate the necessary change notices for Hydra when only specific assets have changed?
This seems like it would be a common need for any cloud/streaming asset pipeline built on USD, so I’m curious if others have run into the same issue or found a cleaner solution.
A few pointers for you. I don’t think this is relevant, but if you have assets you’re streaming that are loaded directly by hydra (e.g. textures, or anything indicated by an “SdfAssetPath” in USD), you can tell hydra those are invalid through HdResourceRegistry::ReloadResource: OpenUSD/pxr/imaging/hd/resourceRegistry.h at release · PixarAnimationStudios/OpenUSD · GitHub .
If the thing you’re streaming is USD layers, you’ll need to tell USD to recompose, but recomposition will send a notice to Hydra telling it which prims/properties changed and Hydra should mark those invalid appropriately, and load them on the next frame.
If that’s not working for you, there are a few debug flags that will print out diagnostics that might help. If you set the env var TF_DEBUG=”USDIMAGING_CHANGES”, this prints debug info when hydra gets a change notice from USD. Most libraries have a similar debug flag you can set, if you want to chase things down the rabbit hole, e.g. “USD_CHANGES”, “SDF_CHANGES”, “PCP_CHANGES”, etc.
Generally, this pipeline works and is pretty well tested as long as you (a) trigger recomposition; and (b) call UsdImaging’s “ApplyPendingUpdates()” to forward any accumulated invalidations.
Hope this helps, and if you figure it out please post back here with what the issue was!
Thanks for the detailed breakdown — really helpful. In my setup I’m streaming USD layers as well as MaterialX materials and textures, so both of the paths you describe are relevant.
For triggering recomposition, what I’ve found works well is calling UsdStage::Reload. It handles everything in one shot — layer reloading, recomposition, and the downstream change notices to Hydra — and from what I can tell it does a good job of determining what actually changed without redundantly reprocessing anything that didn’t.
Good to know about HdResourceRegistry::ReloadResource for asset-level invalidation as well — I’ll keep that in mind if I run into cases where textures or other SdfAssetPath-referenced assets need an explicit nudge.
One other thing that helped me a lot in getting the invalidation pipeline right was studying the resolver example under extras/usd/examples/usdResolverExample in the USD source tree. Walking through that code gave me a much clearer understanding of how dirty notifications propagate and how to properly signal the stage about resolver-level changes. Definitely worth a look for anyone working on a similar streaming setup.