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

Encapsulation in Instancer #4029

Merged

Conversation

danieldresser-ie
Copy link
Contributor

@danieldresser-ie danieldresser-ie commented Nov 25, 2020

This is very early, but it looks like it's going to work fine. There's some cleanup required for how affects() is handled, and I should probably do a bit more testing, but after switching to a method where I don't use contexts, this is looking reasonably good.

The main thing I could use feedback on is the Version 1 and Version 2 PRs. Originally, I did what we talked about: adding internal versions of [compute/hash]Branch[ChildNames/Object/Set], which take a boolean for whether they are being evaluated outPlug() or capsuleScenePlug(), and when appropriate, calling them with inCapsule=true from an overridden hashObject when evaluating the capsuleScene plug. But when it came time to implement computeSet, I encountered a problem: I would have to reimplement all the logic from BranchCreator::computeSet, which is kind of complicated, and sounds like it may change in the future to increase parallelism.

Then I realized that I got just turn this logic inside out: the logic for computeSet on outPlug when encapsulating is trivial ( no sets are added to until you expand the capsules, so the input sets can just be passed through ( Oh wait, I guess I do still need to check if the set exists in the input, and return an empty set if it doesn't? ) ). This meant that I could just have the overridden computeSet handle the special easy case of computing the sets when encapsulating, instead of using any of the default mechanism, and then computeBranchSet can be set up to always do the more complicated default behaviour without checking the encapsulate plug.

For sets, this is both cleaner and simpler - but it's a bit annoying that the structure is now quite different for object/childNames and for sets. In version 2, I apply the same transform to object/childNames, which I think also feels a bit cleaner, but it costs an extra call to parentAndBranchPaths, which is probably not worth it.

So, I still need to make a decision on this, and do some cleanup, and it might make sense to add support for the prototype encapsulation as well before putting this up for merging. But it all feels like it's going reasonably smoothly so far.


void Instancer::plugDirtied( const Gaffer::Plug *plug )
{
if( plug->parent() == outPlug() )
Copy link
Member

Choose a reason for hiding this comment

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

Remind me to talk to you about this later - I think we can do better than invalidate the capsule every time the out plug changes. It should be sufficient to depend only on the poor man's hash of prototypesPlug() and the exact hash of the points object. The goal is not to invalidate the capsule for any old change in the main input scene.

@danieldresser-ie
Copy link
Contributor Author

Quick update at end of day: I thought this was pretty well ready to go, then did some interactive testing, and discovered a problem:

You suggested that we could improve performance by using the actual hash of the points object, because the Capsules don't change if the hash of the points object doesn't change. This is true ... the problem is that the capsules are invalidated based on the dirtyCount, and the dirtying of the points object feeds into that. I could just hash in the dirtyCount of the points object, but it would be nice if reusing the points object did reuse the capsules, since they are still correct, we just don't know that they're valid.

I got as far as adding a test showing the problem, but didn't get any further. There may be simple solution that I will realize as soon as I think about it on Monday.

@danieldresser-ie
Copy link
Contributor Author

Haven't really concluded anything other than our conversation this morning, but I did confirm that everything appears to work fine if I just comment out throwIfExpired.

@danieldresser-ie
Copy link
Contributor Author

After rebasing onto the new verison of the other PR, this now appears to be working.

@danieldresser-ie danieldresser-ie marked this pull request as ready for review December 1, 2020 23:42
@danieldresser-ie
Copy link
Contributor Author

Checked and noticed the failing test ... was just the UI failing, so I quick added some documentation ... and noticed the plug name is too long to fit in the Node Editor.

I guess that probably needs fixing? I would accept basically any proposal other than "encapsulateInstances", which I still feel describes precisely the wrong thing. If we're not doing "encapsulatePrototypes" for now, maybe we just call it "encapsulate"?

@danieldresser-ie
Copy link
Contributor Author

Resolved my last comment by setting label. Ready for review

Copy link
Member

@johnhaddon johnhaddon left a comment

Choose a reason for hiding this comment

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

Thanks Daniel, this is looking good. I've made quite a few little nitpicky comments inline, but overall I'm really pleased with how simple you've managed to make it look - nice one.

I did a bit of testing here with a just over a million instances, and things are looking good. This seems to add around 1% overhead from the additional checks when we're not taking advantage of encapsulation, which I don't think is a big deal. In return, the set generation is greatly improved as we had hoped. Testing with a prototype with 3 sets, encapsulated set generation is down to 0.002s vs 10s for a downstream Encapsulate node. Memory usage also drops more than a 1G. I think this will be a significant improvement for the production scenes we're targeting.

Thanks!
John

include/GafferScene/Capsule.h Outdated Show resolved Hide resolved
src/GafferScene/Capsule.cpp Outdated Show resolved Hide resolved
include/GafferScene/Capsule.h Outdated Show resolved Hide resolved
include/GafferScene/Capsule.h Outdated Show resolved Hide resolved
include/GafferScene/Capsule.h Outdated Show resolved Hide resolved
Comment on lines 157 to 160
# Then set it back ( to make sure that we don't pull expired Capsules out of the cache )
freezeTransform["enabled"].setValue( False )
self.assertScenesEqual( unencap["out"], instancer["out"] )
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain how this checks against expired Capsules?

python/GafferSceneUI/InstancerUI.py Outdated Show resolved Hide resolved
python/GafferSceneUI/InstancerUI.py Outdated Show resolved Hide resolved
BranchCreator::hashBranchObject( parentPath, branchPath, context, h );
h.append( reinterpret_cast<uint64_t>( this ) );
/// We need to include anything that will affect how the capsule will expand
/// \todo : This should use `h.append( Capsule::capsuleDirtyCount( prototypesPlug() ) );`
Copy link
Member

Choose a reason for hiding this comment

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

This method doesn't exist at the moment, so we should probably say talk about ignoring dirtiness on the globals plug rather than using capsuleDirtyCount().

Changes.md Outdated
@@ -7,6 +7,7 @@ Features
--------

- Unencapsulate : Added new node to expand capsules created by Encapsulate back into regular scene hierarchy. This discards the performance advantages of working with capsules, but is useful for debugging, or when it is necessary to alter a capsule's contents downstream.
- Instancer : Added "encapsulateInstanceGroups" option, which outputs the instances within capsules. This improves performance in some cases.
Copy link
Member

Choose a reason for hiding this comment

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

Let's elaborate a little bit here, to mention why this is better than downstream encapsulation.

@danieldresser-ie danieldresser-ie force-pushed the instancerEncapNoCon branch 3 times, most recently from 4e9993c to 4c73836 Compare December 10, 2020 02:35
@danieldresser-ie
Copy link
Contributor Author

Addressed comments in separate commit, will need squashing after review.

Only comment I have is that in naming the UI section "Encapsulate", my original thought was that it makes the UI name match the plug name "Encapsulate" > "Instance Groups" matches "encapsulateInstanceGroups", but I don't feel strongly about this, so I've renamed to "Encapsulation" as requested.

I probably need to rebase this again onto the maintenance branch as well? We don't want to target master any more?

@johnhaddon johnhaddon changed the base branch from master to 0.59_maintenance December 10, 2020 14:38
@johnhaddon johnhaddon dismissed their stale review December 10, 2020 14:38

Requested changes made

@johnhaddon
Copy link
Member

Thanks Daniel, I spotted a couple of typos so I've taken the liberty of fixing those and tweaking the release notes slightly at the same time as doing a final review and rebasing to 0.59. Will merge once CI is done.

@johnhaddon johnhaddon merged commit e95d3c1 into GafferHQ:0.59_maintenance Dec 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants