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

MAYA-128407 fix edit-target loops in proxy shape compute #2955

Merged
merged 4 commits into from
Mar 21, 2023

Conversation

pierrebai-adsk
Copy link
Collaborator

The problem is recursive interactions between multiple actors.

First actor: the ProxyAccessor class.

This class is only vaguely documented, that is there is a mechanical description but not an explanation of why it needs to exists nor why it is written as it is. It's mechanical purpose, as I understand it from its docs, is to copy input plugs into the proxy shape to stage data and copy stage data to output plugs. For some reason which are not explained, it writes its data to the session layer. To do so, it temporarily sets the target layer to the session layer.

Second actor: the ProxyShapeBase class.

The class is the representation of the USD stage as a Maya node. As part if its computation, it creates the stage. It holds multiple attributes to do so:

  • The root layer
  • The session layer
  • The list of muted layers
  • The load/unload state of various payload
  • The current edit target layer.

And, in its implementation of its computation uses the ProxyAccessor. So, computing the ProxyShapeBase use a ProxyAccessor, which switch the target layer.

Third actor: the Edit Target Notifications

In order for the ProxyShapeBase to set the correct edit target when computed, it needs to know when the edit target has changed. Otherwise, after the user changed the edit target, recomputing the ProxyShapeBase would set the edit target to the old target. So the ProxyShapeBase register a notification listener to be told when the edit target changes. When the edit target changes, the notification listener sets the edit-target attribute on the ProxyShapeBase so that it sets the correct target if it is recomputed.

End Result

So, the sequence of events is:

  • The ProxyShapeBase is recomputed.
  • The ProxyAccessor changes the target to the session layer.
  • This trigger the edit-target change notification
  • This updates the ProxyShapeBase attribute
  • This dirties the ProxyShapeBase
  • The ProxyShapeBase compute ends.
  • This destroys the ProxyAccessor
  • This reset the edit target to its previous value.
  • This trigger the edit-target change notification
  • This updates the ProxyShapeBase attribute
  • This dirties the ProxyShapeBase
  • And... now the ProxyShapeBase will get recomputed again when accessed.

There are two ways to break the chain:

  • Detect temporary changes in the edit target and ignore them.
  • Not dirty the ProxyShapeBase when the edit target change.

The first one would be dangerous since if a recompute is triggered at that moment, it would use the incorrect edit target. OTOH, it is unclear what is the correct edit target at that point: is it the temporary edit target set by the proxy accessor or the edit target set by the user?

The second one can be done by keeping the current edit target in a member variable in the ProxyShapeBase and only use the attribute at load time to initially fill that variable, say on the first compute. I think that is what I will do to fix the problem.

  • Add a member variable to ProxyShapeBase to keep track of the current edit target.
  • Fill it on first compute.
  • Update it when the edit target change, via the notifications.
  • Only save the edit target on save (this was already existing).
  • Refactor edit-target helper functions to support all this.

The problem is recursive interactions between multiple actors.

First actor: the ProxyAccessor class.

This class is only vaguely documented, that is there is a mechanical description but not an explanation of why it needs to exists nor why it is written as it is. It's mechanical purpose, as I understand it from its docs, is to copy input plugs into the proxy shape to stage data and copy stage data to output plugs. For some reason which are not explained, it writes its data to the session layer. To do so, it temporarily sets the target layer to the session layer.

Second actor: the ProxyShapeBase class.

The class is the representation of the USD stage as a Maya node. As part if its computation, it creates the stage. It holds multiple attributes to do so:

- The root layer
- The session layer
- The list of muted layers
- The load/unload state of various payload
- The current edit target layer.

And, in its implementation of its computation uses the ProxyAccessor. So, computing the ProxyShapeBase use a ProxyAccessor, which switch the target layer.

Third actor: the Edit Target Notifications

In order for the ProxyShapeBase to set the correct edit target when computed, it needs to know when the edit target has changed. Otherwise, after the user changed the edit target, recomputing the ProxyShapeBase would set the edit target to the old target. So the ProxyShapeBase register a notification listener to be told when the edit target changes. When the edit target changes, the notification listener sets the edit-target attribute on the ProxyShapeBase so that it sets the correct target if it is recomputed.

End Result

So, the sequence of events is:

- The ProxyShapeBase is recomputed.
- The ProxyAccessor changes the target to the session layer.
- This trigger the edit-target change notification
- This updates the ProxyShapeBase attribute
- This dirties the ProxyShapeBase
- The ProxyShapeBase compute ends.
- This destroys the ProxyAccessor
- This reset the edit target to its previous value.
- This trigger the edit-target change notification
- This updates the ProxyShapeBase attribute
- This dirties the ProxyShapeBase
- And... now the ProxyShapeBase will get recomputed again when accessed.

There are two ways to break the chain:

- Detect temporary changes in the edit target and ignore them.
- Not dirty the ProxyShapeBase when the edit target change.

The first one would be dangerous since if a recompute is triggered at that moment, it would use the incorrect edit target. OTOH, it is unclear what is the correct edit target at that point: is it the temporary edit target set by the proxy accessor or the edit target set by the user?

The second one can be done by keeping the current edit target in a member variable in the ProxyShapeBase and only use the attribute at load time to initially fill that variable, say on the first compute. I think that is what I will do to fix the problem.

- Add a member variabel to ProxyShapeBase to keep track of the current edit target.
- Fill it on first cmpute.
- Update it when the edit target change, via the notifications.
- Only save the edit target on save (this was already existing).
- Refactor edit-target helper functions to support all this.
@pierrebai-adsk pierrebai-adsk added bug Something isn't working adsk Related to Autodesk plugin labels Mar 20, 2023
When the shared flag of the proxy shape is toggled, the session layer changes, so we need to update the edit target if the target was on the session layer.
Copy link
Collaborator

@vlasovi vlasovi left a comment

Choose a reason for hiding this comment

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

Looks good. Thanks for removing the "on idle" callback.

@pierrebai-adsk pierrebai-adsk added the ready-for-merge Development process is finished, PR is ready for merge label Mar 21, 2023
@seando-adsk seando-adsk merged commit 2e02d71 into dev Mar 21, 2023
@seando-adsk seando-adsk deleted the bailp/MAYA-128407/edit-target-loop branch March 21, 2023 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
adsk Related to Autodesk plugin bug Something isn't working ready-for-merge Development process is finished, PR is ready for merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants