Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure light collections are dirtied on creation #1653

Conversation

aloysbaillet
Copy link
Contributor

Description of Change(s)

We found that when undoing the deletion of a light with an active collection, the re-creation of that light was not dirtying the content of the collection.

It is unfortunately quite tricky to provide a test for this use case, but we have one internally in Omniverse...
Our test goes like this:

  • create 2 cubes
  • create a light
  • set the light's lightLink collection to refer to cube2
  • check in viewport with a light-collection-enabled renderer that things are OK
  • delete the light
  • undo that deletion
  • check in viewport with a light-collection-enabled renderer that things are OK again (it wasn't without this fix)

@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from 9e0776e to ce682b6 Compare October 12, 2021 08:58
@spitzak
Copy link

spitzak commented Oct 12, 2021

We ran into this as well, but it was pretty simple to have the renderDelegate update things due to the creation of the light and the calling of Sync() on it, so I am not absolutely certain this dirtying is needed

@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from ce682b6 to 78804af Compare October 12, 2021 23:24
@aloysbaillet
Copy link
Contributor Author

Thanks Bill, I'm still discovering the Hydra world... but in our render delegate the Light::Sync was indeed called, but each linked geometry rprim wasn't and we need them called to re-register them with the light link. I'm curious how you made it work?

@spitzak
Copy link

spitzak commented Oct 13, 2021 via email

@aloysbaillet
Copy link
Contributor Author

Fair enough :)
I wanted to avoid marking all prims dirty though, the proposed change only marks the collection members dirty...

@jilliene
Copy link

Filed as internal issue #USD-6961

@tcauchois
Copy link
Contributor

Hey Aloys,

Like I mentioned on your other PR, I'm a bit hesitant to have special case code in delegate.cpp since it becomes hard to maintain. There's also a few bits you're missing. This will be a bit involved to fix but I'll try to lay out the pieces and answer any questions.

First up, we have an object UsdImaging_CollectionCache that actually answers all of the queries, both GetLightParamValue(lightLink) and GetCategories(rprim). Here's the class: https://github.com/PixarAnimationStudios/USD/blob/release/pxr/usdImaging/usdImaging/collectionCache.h ... and here's where we populate it: https://github.com/PixarAnimationStudios/USD/blob/release/pxr/usdImaging/usdImaging/lightAdapter.cpp#L131 ... In order to keep the collection cache up to date with any changes, I'd recommend updating lightAdapter.cpp and lightFilterAdapter.cpp to call UpdateCollection in TrackVariability (which is already there); call UpdateCollection in ProcessPropertyChange if the collection changes (and return HdLight::DirtyParams); and call RemoveCollection in _RemovePrim. This way the results of any calls into the collection cache will always be up-to-date.

The next piece you need is hydra dirty bit tracking. Ideally, you could do this when you call UpdateCollection; the collection cache removes a bunch of gprims from the collection list, and adds a bunch of other ones, and you could just produce a list of paths to mark with DirtyCategories. However, TrackVariability (for example) is called multi-threaded and can't call the hydra change-tracker, which isn't threadsafe. And neither TrackVariability nor ProcessPropertyChange have a UsdImagingIndexProxy, which is the class needed to call MarkDirty.

The way out of this that I see is for the collection cache to keep a dirty gprim list. Every time you call RemoveCollection or UpdateCollection, add hydra paths to an SdfPathSet (or Vector) on the collection cache itself. At the end of UsdImagingDelegate::ApplyPendingUpdates(), which is our function that applies USD edits to imaging, loop through this set calling MarkDirty(DirtyCategories); I'm imagining putting that loop here https://github.com/PixarAnimationStudios/USD/blob/release/pxr/usdImaging/usdImaging/delegate.cpp#L1040 ... right after _ExecuteWorkForVariabilityUpdate. Or the other option, of course, is Bill's approach of marking all rprims dirty with DirtyCategories whenever the collections change. That's faster if your light collections tend to be big. (Note that the trivial collection of "/" avoids all of these codepaths entirely).

That should do a much better job of handling the category change-tracking.

Hopefully this makes sense! Any work to fix this up is super appreciated, and I'm happy to answer whatever questions you have about the code.

Thanks,
Tom

@aloysbaillet
Copy link
Contributor Author

Thanks Tom, I'll look into this!

@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from 78804af to 73d78c8 Compare April 27, 2022 11:59
{
*timeVaryingBits |= HdLight::DirtyBits::DirtyCollection;
}
else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can skip the else here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, can just call _UpdateCollectionsChanged. I don't think collections are allowed to be time-varying? And if you did want to check that, instead of seeing if the collection has new contents, you'd want to ask whether the attributes are time varying.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the call altogether as the attributes cannot be animated... I'm guessing that if timesamples are added on the includeRoot bool that could cause some issues though?

@@ -78,15 +97,16 @@ UsdImaging_CollectionCache::UpdateCollection(UsdCollectionAPI const& c)
_pathsForQuery[query].insert(path);
_idForPath[path] = id;

_MarkCollectionContentDirty(stage, query);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like there's some missing bits here... If _queryForId[id] before you update it != query, also _MarkContentDirty(stage, _queryForId[id])?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RemoveCollection call at the beginning of UpdateCollection will mark the previous collection content dirty, wouldn't this cover it?

{
// If there are any exlusion we have to consider all previously excluded paths dirty
// As there is no API to query excluded paths we mark all prims in the Stage dirty
_allPathsDirty = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if the query has exclude paths, I'd still expect UsdComputeIncludedPathsFromCollection to come up with the right list. That should return the set of paths that pass both the include & exclude rules, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, but prims that were previously excluded from the collection would not be returned in the include set, and these also need to be marked dirty...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually as the RemoveCollection call will catch all paths from the outgoing collection, the UpdateCollection should be able to safely ignore the excluded paths... Will test that further!

@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from 8d1644a to 94e4ec5 Compare April 28, 2022 01:24
@aloysbaillet
Copy link
Contributor Author

I've cleaned and simplified the code further, also fixed some formatting inconsistencies.
The UsdImagingLightAdapter::ProcessPropertyChange method now returns HdLight::DirtyBits::DirtyCollection when it detects a collection change (using hashes for comparison, but without having to store them).

I'm still having one refresh issue that I'm chasing but I'm confident it is a problem in our render delegate (I had to change it quite a lot to handle HdLight::DirtyCollection properly).
I'm quite confident the prman render delegate will need updating to take advantage of the now-working DirtyCollection flag, but I'm not sure if I'll be able to do that (I think I would need a license first ;) ).

@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from 0127a1e to 269cbb3 Compare April 29, 2022 07:31
@aloysbaillet aloysbaillet force-pushed the dirty-light-collections-on-creation branch from 269cbb3 to 6d64dee Compare April 29, 2022 07:32
@aloysbaillet
Copy link
Contributor Author

I've fixed a compilation error (UsdLuxLight->UsdLuxLightAPI as I was testing on an older USD version sorry!) and @sirpalee kindly tested these changes with success using the Arnold render delegate.

@pixar-oss pixar-oss merged commit d251bd3 into PixarAnimationStudios:dev May 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants