Page MenuHome

RNA Collections: Synchronize view layer in the callback to set flags
AbandonedPublic

Authored by Germano Cavalcante (mano-wii) on Sep 16 2021, 8:13 PM.

Details

Summary

This is a convenient change if we want to animate the visibility of a collection (See D12469).

Currently, when a collection flag needs to be set, BKE_main_collection_sync(bmain) needs to be called to recreate all Bases and all hierarchy of collections in all ViewLayers.

Adding this function to an update operand in Depsgraph would be inefficient for animation since the depsgraph operand is always called during frame change (it doesn't matter if the flag has changed or not).

(D12469 has a workaround by creating a function that reduces the scope of synchronization).

The solution for this patch is to synchronize all ViewLayers when setting the flag instead of when updating.

This causes the BKE_main_collection_sync(bmain) API to only be called when the flag changes.

Also BKE_main_collection_sync(bmain) has been edited to work with scene and ViewLayer evaluated.

Diff Detail

Repository
rB Blender
Branch
collection_update (branched from master)
Build Status
Buildable 17108
Build 17108: arc lint + arc unit

Event Timeline

Germano Cavalcante (mano-wii) requested review of this revision.Sep 16 2021, 8:13 PM

Fix layer_restrict flag

  • Fix error introduced in last commit: update nested collections flags
Germano Cavalcante (mano-wii) planned changes to this revision.Sep 16 2021, 9:02 PM

Investigate Bases linked to different collections

  • Use existing sync API

This avoids having to duplicate the code.
Also the existing API resolves all the details (like local collections).
There are a lot of details to investigate, so better use the existing (non-optimized) API.

Germano Cavalcante (mano-wii) retitled this revision from Collections: Optimize flag synchronization to RNA Collections: Synchronize view layer in the callback to set flags.Sep 16 2021, 10:18 PM
Germano Cavalcante (mano-wii) edited the summary of this revision. (Show Details)
Sergey Sharybin (sergey) requested changes to this revision.Sep 17 2021, 10:03 AM

It is only depsgraph evaluation which can modify datablocks in the graph. You must not modify those from the outside, as it is not only thread-unsafe, but also violates evaluated state of the graph. This is also why one must not expose the internal registry of graphs.

The only thing which fits into design is to perform ID tags and let the graph to react to those when this is convenient for the graph.

This revision now requires changes to proceed.Sep 17 2021, 10:03 AM

The idea is to call DEG_get_all_registered_graphs only during depsgraph evaluation.
BKE_layer_collection_flag_set is called only by the RNA.
When the value of an animated property changes due to frame change, the RNA callback is called twice: once for the original id and once for the evaluated id. (See BKE_animsys_evaluate_animdata and animsys_evaluate_fcurves).
Since the callback is only called during depsgraph evaluation, I believe it's too late for perform ID tags :\

So, I don't see any other way that is more efficient than finding and updating the evaluated IDs.

How about creating a function: DEG_find_current_evaluated_graph? So it could return NULL if it is not called during the depsgraph evaluation.

The idea is to call DEG_get_all_registered_graphs only during depsgraph evaluation.

Multiple dependency graphs might be evaluating in parallel.
Additionally, changing data which does not belong to you is not a good idea either.

When the value of an animated property changes due to frame change, the RNA callback is called twice

What callback you're talking about?

How about creating a function: DEG_find_current_evaluated_graph? So it could return NULL if it is not called during the depsgraph evaluation.

If code is executed as part of depsgraph evaluation check the callstack and eventually you'll see depsgraph passed explicitly (for example, see BKE_mesh_eval_geometry()).
If you are asking about accessing despgraph which is being evaluated from outside of depsgraph evaluation callback, then it is a wrong way of thinking of a solution.

What callback you're talking about?

I mean the functions set for a property. For example rna_Collection_hide_viewport_set in:

RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_viewport_set");

How about creating a function: DEG_find_current_evaluated_graph? So it could return NULL if it is not called during the depsgraph evaluation.

If code is executed as part of depsgraph evaluation check the callstack and eventually you'll see depsgraph passed explicitly (for example, see BKE_mesh_eval_geometry()).
If you are asking about accessing despgraph which is being evaluated from outside of depsgraph evaluation callback, then it is a wrong way of thinking of a solution.

The idea of DEG_find_current_evaluated_graph would be to return NULL if called outside of depsgraph evaluation. (But maybe this is complex due to the multithreaded character... needs investigation).


In summary the problem is:
When changing the visibility of a collection, the property callback is called and updates the collection and all ViewLayers that contain that collection (That's why all ViewLayers from bmain are fetched).
But if the property is animated and is changed during the play, the depsgraph operand calls the rna callback for both the original collection and the evaluated collection.
But if the collection is evaluated, no ViewLayer in bmain will have this collection. So we need to find the evaluated ViewLayer(s).
However, the depsgraph parameter is not passed to rna callbacks.
(How to get evaluated ViewLayer inside a rna callback?)

I don't understand what is the problem of set RNA callback being called for evaluated and original datablocks? This is an intended behavior of the system.

When changing the visibility of a collection

To my knowledge this is not currently supported.

But if the collection is evaluated, no ViewLayer in bmain will have this collection. So we need to find the evaluated ViewLayer(s).

Why would RNA need to find view layer?
To me it sounds like you're trying to replicate depsgraph's job in RNA callback.

Why would RNA need to find view layer?
To me it sounds like you're trying to replicate depsgraph's job in RNA callback.

To implement collection visibility animation, we need to:

  • change the collection flag through the animation
  • update ViewLayers and View3D Bases
  • Somehow update the collection and Bases of the evaluated ViewLayers and View3D.

At first it seems that it would be simple to solve this with a simple DEG_id_tag_update in the collection with all the necessary relations created.
But in an animation, the flag is changed during depsgraph evaluation. (Can we call DEG_id_tag_update in this case?)

We could add a node to always update the evaluated ViewLayer when the frame changes and a collection is animated (This is the D12469 solution).
But this is inefficient, hardly a visibility would have to change more than once in an animation, so why update the ViewLayer on every frame?
It needs to be updated only when the flag changes. But can we create a node relation during depsgraph evaluation?

Talked to Dalai to understand the scope a bit better.

So, to make collections visibility animatable we need to make sure all collections with animated visiiblity are in the depsgraph (currently there is an optimization which ignores disabled collections).
Look at the build_collection in node and relations builders. this is inclusion logic is.
Other place to look at is the DepsgraphBuilder::need_pull_base_into_graph. This is where we do have check based on animated state of proeprty.

Following the examples from above, introduce DepsgraphBuilder::need_pull_collection_into_graph.

To help verifying the graph can use Debug Dedpsgraph addon. Keep the scene small though! The graphviz gets unreabdable very quickly :(

Not sure if we need special treatment for view layers in the evaluated scene. If so, have a look at scene_remove_unused_view_layers.

To properly maintain base flags some modifications to BKE_layer_eval_view_layer_indexed might be needed (maybe even more dedicated operation, not sure from the top of my head where exactly the visiblity and such gets applied from collections to bases).

Somehow update the collection and Bases of the evaluated ViewLayers and View3D.

You can't have topology of the graph depend on animation. Best you can do is to have all data in the graph ready, and have its visibility evaluated to false.

See some notes above.

These issues have already been considered in D12469.
The purpose of this patch is to make possible a more efficient solution for D12469.
BKE_layer_eval_view_layer_indexed needs to be changed so that all ViewLayer Bases are updated.
I just wanted to avoid unnecessary updating.

  • Implemente DEG_find_graph_evaluating

Nothing definitive, but better than the previous solution

Focus on a solution which fits into a design, and look into what the bottlenecks are and how to solve them after that.

  • Implemente DEG_find_graph_evaluating

Nothing definitive, but better than the previous solution

  • You might have multiple dependency graphs evaluating at the same time.
  • You might tweak setting in in the interface while, say, single dependency graph used by icon rendering is evaluating.
  • DEG_find_from_id

I thought maybe depsgraph evaluation was blocked by depsgraph.
There are some operants that work on the original id and it doesn't seem to be thread-safe :\
Anyway I updated the patch just to keep it more bug-proof.

I thought maybe depsgraph evaluation was blocked by depsgraph.

There is supposed to be only one active dependency graph.

Anyway I updated the patch just to keep it more bug-proof.

Not so much sure about this, and it still violates a design or two:

  • Moves evaluation part outside of depsgraph
  • Accesses interface data from code which is supposed to be run during depsgraph evaluation
  • Introduces non-trivial RNA set() function
  • Is only a dependency graph which is allowed to modify evaluated data
  • BKE_scene_collection_sync can not be used on evaluated data as it potentially changes topology of the graph
  • Not sure what ensures valid state of view layer's object_bases_arrayafter the bases modification

I don't understand why visibility synchronization is such an expensive operation. And trying to bypass a conventional flow of evaluation will bite you back in one way or another.

For animation support of Exclude option one thing you can try doing is to mimic its behavior to as if it modifies visibility, but but "locally" inside of the evaluated domain. Not sure how easy this is in practice, but attempting to support Exclude as it is for animation is not going to be trivial.

Better to invest time on D12469