Page MenuHome

Depsgraph: support flushing parameters without a full COW update
ClosedPublic

Authored by Campbell Barton (campbellbarton) on May 25 2021, 4:03 AM.

Details

Summary

Avoid computationally expensive copying operations
when only some settings have been modified.

This is done by adding support for updating parameters
without tagging for copy-on-write.

Currently only mesh data blocks are supported,
other data-blocks can be added individually.

This prepares for changing values such as edit-mesh auto-smooth
angle in edit-mode without duplicating all mesh-data.
The benefit will only be seen when the user interface
no longer tags all ID's for copy on write updates.

ID_RECALC_GEOMETRY_ALL_MODES has been added to support situations
where non edit-mode geometry is modified in edit-mode.
While this isn't something user are likely to do,
Python scripts may change the underlying mesh.


Notes

  • When allocated arrays in the source mesh have been freed an explicit copy-on-write tag is now needed (this patch replaces ID_RECALC_GEOMETRY with ID_RECALC_COPY_ON_WRITE where necessary).

    Otherwise a mesh in edit-mode could have it's COW-id data-block pointing to freed memory (when memory is shared between the original and the copied data). In practice this only happens in a few places (such as flushing edit-data to the ID data-block for rendering). Although it's possible for Python to cause this situation when performing mesh editing operations while still being in edit-mode - so it's important the correct recalculation tag is used.

Open Topics

  • Exactly what counts as a parameter should to be clearly defined.

    Currently data which is directly attached to the ID data-block is used. For mesh-data this happens to be straightforward. For other ID types the division isn't so clear, for example, would we consider a changed modifier value to be the parameter of an object? (I'd this makes sense, however it complicates the update function).
  • Some details from this patch that should be changed, if the general design is acceptable.
    • ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW moved to a function.

Further Work

While looking into this patch I found other cases where copy-on-write is performed which can be avoided.

  • Even though this patch removes copy-on-write updates when changing parameters, rna_property_update is currently tagging ID_RECALC_COPY_ON_WRITE for all ID types that use copy-on-write.

    This could be removed as neither F-curve or the Python API do this, however I'd rather this be done as part of a separate patch as it has wider implications for non-animated values that rely on this for updates.
  • We may want to have more control to limit when a full copy-on-write is performed.

    As far as I can see there is no way to express that a parameter changed that should re-evaluate geometry without running a redundant copy-on-write.

    For example changing the auto-smooth angle only needs to copy the parameter & recalculate modifies, there is no need to copy over all geometry data from the original mesh.

Diff Detail

Repository
rB Blender
Branch
TEMP-D11377-UPDATE-v2 (branched from master)
Build Status
Buildable 15397
Build 15397: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Campbell Barton (campbellbarton) retitled this revision from Depsgraph: data blocks recalculating parameters without triggering a full COW update to Depsgraph: data blocks recalculating parameters without a full COW update.
Campbell Barton (campbellbarton) retitled this revision from Depsgraph: data blocks recalculating parameters without a full COW update to Depsgraph: support flushing parameters without a full COW update.
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)

Some quick feedback which should be easy to address.
Seems like a step in the right direction!

source/blender/blenkernel/intern/mesh_validate.c
1186

Should be using ID_RECALC_PARAMETERS instead of ID_RECALC_COPY_ON_WRITE.

Should really add a comment that ID_RECALC_COPY_ON_WRITE is the last resort when nothing else fits =\

source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
1208–1215

Don't inline evaluation function. It'll grow out of maintainable state rather quickly.

source/blender/depsgraph/intern/node/deg_node_component.h
172

Think it's more readable to avoid such macro. It is used for a single case. Just do ParametersComponentNode similar to BoneComponentNode.

178

Should check for whether ID is expanded. Either as a safety, or as an assert. But we shouldn't quietly returning false here.

source/blender/makesdna/DNA_ID.h
680

Remove "currently".

I'll look into making these changes 1 comment noted inline.

source/blender/blenkernel/intern/mesh_validate.c
1186

Are you sure about this? Changing the material means the copy-on-write version should have it's polygon face materials updated too, then the modify a step should be updated.

Campbell Barton (campbellbarton) marked an inline comment as not done.May 26 2021, 6:02 PM
Campbell Barton (campbellbarton) added inline comments.
source/blender/blenkernel/intern/mesh_validate.c
1186

Correction: then the modifiers should be updated

source/blender/blenkernel/intern/mesh_validate.c
1186

Copy-on-write is implied, Tagging with ID_RECALC_PARAMETERS should also tag for the ID_RECALC_COPY_ON_WRITE (in the cases the component you're tagging returns truth from need_tag_cow_before_update()).

From the patch description:

Exactly what counts is the perimeter should to be clearly defined.

I think this sentence should also be more clearly defined ;-) I'm guessing you meant "what counts as the parameters".

source/blender/blenkernel/intern/mesh.c
905 ↗(On Diff #37437)

I'm not a fan of adding a boolean to optionally add/remove functionality from a function. To me this just means it should be split up into separate functions, which can then be called (or not) where appropriate.

See Robert C. Martin, Clean Code, G15: Selector Arguments.

source/blender/makesdna/DNA_ID.h
617–618

This is linguistically a bit weird. How about this?

When memory in the original ID has been modified, and that memory might be shared with the copy-on-write data-block, explicit use of #ID_RECALC_COPY_ON_WRITE is required.

source/blender/makesrna/intern/rna_mesh.c
222–240

This function should be renamed to reflect its purpose better, given that there is now a distinction between "mesh update" and "mesh update with geometry and parameters". When you take out "geometry and paramters", what else is left? How should someone choose between one mesh update function and the other?

248

This may need a bit more explanation. If anything, adhere to the code style.

Campbell Barton (campbellbarton) marked 7 inline comments as done and an inline comment as not done.Jun 17 2021, 7:38 AM
Campbell Barton (campbellbarton) added inline comments.
source/blender/blenkernel/intern/mesh.c
905 ↗(On Diff #37437)

Also not a fan of this, the minor change was to avoid too much noise in this patch, as noted in patch text:

BKE_mesh_copy_settings_ex could be replaced with a dedicated function, or we could have a callback in IDTypeInfo.

I've since split this into a separate function in master BKE_mesh_copy_parameters & BKE_mesh_copy_parameters_for_eval since the second function is specifically for evaluated meshes as it doesn't handle user ID user-counts (also added assert so it's only ever used for non-main meshes).

source/blender/makesrna/intern/rna_mesh.c
222–240

Renaming here causes noise, an issue with naming this function is that it uses DEG_id_tag_update(id, 0) which is generally discouraged and doesn't have a name as far as I know, I'll rename rna_Mesh_update_data to rna_Mesh_update_data_all since zero is a signal to tag everything for updates.

248

I'm not sure what you mean exactly.

Minor changes to if checks or poor comments can be handled separately to this patch - committed to master directly for example.

Campbell Barton (campbellbarton) marked 2 inline comments as done.
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
  • Update based on review.

Rebase on master, which includes changes based on feedback here.

  • Comment about zero-user ID updates was vague, move to a single more descriptive comment.
  • Use early return.
source/blender/blenkernel/intern/mesh_validate.c
1186

The issue is geometry won't return true from need_tag_cow_before_update when tagged with ID_RECALC_PARAMETERS because of ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.

  • Declare function with 'override' instead of 'virtual'
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
source/blender/blenkernel/intern/mesh_validate.c
1186

Shouldn't it just tag with both ID_RECALC_GEOMETRY and ID_RECALC_PARAMETERS then, if both need updating?

I don't understand why you are changing DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); with DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);

The ID_RECALC_COPY_ON_WRITE is This is most generic tag which should only be used when nothing else matches. So why changes in geometry do not use ID_RECALC_GEOMETRY?

source/blender/depsgraph/intern/node/deg_node_component.h
206
source/blender/depsgraph/intern/node/deg_node_id.h
132 ↗(On Diff #38446)

Move this to DNA_ID.h, next to ID_TYPE_IS_COW.

  • Use virutal for need_tag_cow_before_update function signature.
  • Move ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW into DNA_ID.h
Campbell Barton (campbellbarton) marked 2 inline comments as done and an inline comment as not done.Jun 22 2021, 8:42 AM
Campbell Barton (campbellbarton) added inline comments.
source/blender/blenkernel/intern/mesh_validate.c
1186

I don't see why ID_RECALC_PARAMETERS would be needed here, only the polygons are modified.

As ID_RECALC_PARAMETERS no longer imply the geometry data gets updated.

source/blender/makesrna/intern/rna_mesh.c
222–240

Updated in master.

248

Updated in master (improved comments, use early return).

I don't understand why you are changing DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); with DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);

The ID_RECALC_COPY_ON_WRITE is This is most generic tag which should only be used when nothing else matches. So why changes in geometry do not use ID_RECALC_GEOMETRY?

This could be changed, in practice it would work in most cases.


  • This patch is meant to be applied before D11337 which changes the behavior of ID_RECALC_GEOMETRY not to do a full COW when in edit-mode.
  • When non edit-mode data is modified while in edit-mode, calling ID_RECALC_GEOMETRY will fail to flush the changes to the evaluated data.
  • If this can be overlooked (I'm not sure what use-case this would break), then it should at least be documented as a possible problem - as the evaluated data is technically stale, even if this case turns out not to be important at the moment.

This could be changed, in practice it would work in most cases.

Don't quite understand the statement. Maybe you can rephrase it to use less indirections ("this" and "it")

My point was: ID_RECALC_COPY_ON_WRITE is more of an exceptional tag, which should barely ever use, especially when the parameters component properly working. If geometry changed tag with ID_RECALC_GEOMETRY, if parameters changed tag with ID_RECALC_PARAMETERS. If this doesn't work in some cases please write the comment in the code about it, and what is to look for.

Again, mental model is: tag with the flag which corresponds to the changed aspect of the ID.

Sergey Sharybin (sergey) requested changes to this revision.Jun 22 2021, 9:52 AM
This revision now requires changes to proceed.Jun 22 2021, 9:52 AM

This could be changed, in practice it would work in most cases.

Don't quite understand the statement. Maybe you can rephrase it to use less indirections ("this" and "it")

Maybe better to give a hypothetical example of something that could fail.

Exporting a mesh:

- The user has enters edit-mode.
- The user exports the 3D model to a file.
- The exporter runs a validate function on the mesh which happens to call `BKE_mesh_validate_material_indices` internally.
- `BKE_mesh_validate_material_indices` tags `ID_RECALC_GEOMETRY`.
- The exporter triggers a depsgraph update so it can access the evaluated output of data that has been validated.
- `ID_RECALC_GEOMETRY` is handled as it mesh is in edit-mode, the evaluated mesh is left as-is, with invalid material indices.

- The exporter reads the mesh from the depsgraph which has invalid material indices cause an index lookup error, breaking the export entirely.

Even if the example above doesn't fail for some reason, this is an example of the kind of problem that could be caused by using ID_RECALC_GEOMETRY in edit-mode when the evaluated Mesh data is expected to be updated (note that in my testing COW is triggered often which complicates trying to show examples of how removing it can fail).

My point was: ID_RECALC_COPY_ON_WRITE is more of an exceptional tag, which should barely ever use, especially when the parameters component properly working. If geometry changed tag with ID_RECALC_GEOMETRY, if parameters changed tag with ID_RECALC_PARAMETERS. If this doesn't work in some cases please write the comment in the code about it, and what is to look for.

Again, mental model is: tag with the flag which corresponds to the changed aspect of the ID.

It may be we need tags to differentiate between geometry updates that are context sensitive (based on object-mode) and changes to object-data.

What's not clear to me is - do we expect arbitrary data that's modified in an ID to be pushed to the evaluated copy, even if it's not used?

I had the impression we don't want evaluated ID's to be stale, however this means ID_RECALC_GEOMETRY can't be used if it skips the mesh data while in edit-mode.

Thanks for more in-depth explanation :)

We indeed don't want stale information in the CoW domain, as it is a straight way to backfire.

Think easiest solution which is quick to implement is to ad alias ID_RECALC_GEOMETRY_ALL_MODES = ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE, and document it something like "Make sure geometry of object and edit modes are both up-to-date in the evaluated datablock. Example usage is when mesh validation modifies the non-edit-mode data, which we want to be copied over to the evaluated datablock." (exact wording surely might need tweaking).

The benefit of this approach would be that things are way more clear for the future-you, so you'll know what exactly is going on, rather than trying to reconstruct a chain of thoughts about "why this generic ID tag was used".

If that's done I think the patch will be good to go.

This seems like a good solution that communicates intent without adding overhead.

Add ID_RECALC_GEOMETRY_ALL_MODES alias for ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE.

source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
1194–1203

One more thing (tm) :(

The name build_parameters_without_cow is misleading. It doesn't build, its an evaluation callback. It should also be in blenkernel, as we don't mix evaluation logic in the builder.

Not sure we have a good place for ID level evaluation yet though. Maybe for now have BKE_mesh_eval_properties and generalize the callback for any ID type when the time comes?

Move ID eval parameter copy function into BKE

Campbell Barton (campbellbarton) marked an inline comment as done.

Remove unrelated changes.

source/blender/blenkernel/intern/mesh_validate.c
1186

This now uses ID_RECALC_GEOMETRY_ALL_MODES which should address comments above.

Sergey Sharybin (sergey) removed 1 blocking reviewer(s): Sybren A. Stüvel (sybren).

Thanks for the update. Design and code seems good now!
Quite sure you did give it an intensive test, so I'm skipping this step :)

P.S. Sybren is on holidays, so changing him to the non-blocking reviewer (so he can still keep an eye here if needed, but I don't think there is anything blocking with this patch).

This revision is now accepted and ready to land.Jun 24 2021, 9:14 AM
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)

Fixed linking error with blender_test.