[Bf-blender-cvs] [0f89bcdbebf] master: Fix depsgraphs sharing IDs via evaluated edit mesh

Sergey Sharybin noreply at git.blender.org
Tue Jan 25 14:32:29 CET 2022


Commit: 0f89bcdbebf5094bd816318774b67c677790ea99
Author: Sergey Sharybin
Date:   Tue Jan 11 15:42:07 2022 +0100
Branches: master
https://developer.blender.org/rB0f89bcdbebf5094bd816318774b67c677790ea99

Fix depsgraphs sharing IDs via evaluated edit mesh

The evaluated mesh is a result of evaluated modifiers, and referencing
other evaluated IDs such as materials.
It can not be stored in the EditMesh structure which is intended to be
re-used by many areas. Such sharing was causing ownership errors causing
bugs like

  T93855: Cycles crash with edit mode and simultaneous viewport and final render

The proposed solution is to store the evaluated edit mesh and its cage in
the object's runtime field. The motivation goes as following:

- It allows to avoid ownership problems like the ones in the linked report.
- Object level is chosen over mesh level is because the evaluated mesh
  is affected by modifiers, which are on the object level.

This patch allows to have modifier stack of an object which shares mesh with
an object which is in edit mode to be properly taken into account (before
the change the modifier stack from the active object will be used for all
objects which share the mesh).

There is a change in the way how copy-on-write is handled in the edit mode to
allow proper state update when changing active scene (or having two windows
with different scenes). Previously, the copt-on-write would have been ignored
by skipping tagging CoW component. Now it is ignored from within the CoW
operation callback. This allows to update edit pointers for objects which are
not from the current depsgraph and where the edit_mesh was never assigned in
the case when the depsgraph was evaluated prior the active depsgraph.

There is no user level changes changes expected with the CoW handling changes:
should not affect on neither performance, nor memory consumption.

Tested scenarios:

- Various modifiers configurations of objects sharing mesh and be part of the
  same scene.

- Steps from the reports: T93855, T82952, T77359

This also fixes T76609, T72733 and perhaps other reports.

Differential Revision: https://developer.blender.org/D13824

===================================================================

M	source/blender/blenkernel/BKE_DerivedMesh.h
M	source/blender/blenkernel/BKE_editmesh.h
M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/BKE_object.h
M	source/blender/blenkernel/intern/DerivedMesh.cc
M	source/blender/blenkernel/intern/crazyspace.c
M	source/blender/blenkernel/intern/editmesh.c
M	source/blender/blenkernel/intern/material.c
M	source/blender/blenkernel/intern/mesh.cc
M	source/blender/blenkernel/intern/mesh_convert.cc
M	source/blender/blenkernel/intern/modifier.c
M	source/blender/blenkernel/intern/object.cc
M	source/blender/blenkernel/intern/object_dupli.cc
M	source/blender/blenkernel/intern/object_update.c
M	source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
M	source/blender/depsgraph/intern/node/deg_node_component.h
M	source/blender/draw/engines/overlay/overlay_armature.c
M	source/blender/draw/engines/overlay/overlay_edit_mesh.c
M	source/blender/draw/engines/overlay/overlay_edit_uv.c
M	source/blender/draw/engines/overlay/overlay_wireframe.c
M	source/blender/draw/engines/select/select_draw_utils.c
M	source/blender/draw/intern/draw_cache.c
M	source/blender/draw/intern/draw_cache_extract.h
M	source/blender/draw/intern/draw_cache_extract_mesh.cc
M	source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
M	source/blender/draw/intern/draw_cache_impl.h
M	source/blender/draw/intern/draw_cache_impl_mesh.c
M	source/blender/draw/intern/draw_cache_impl_subdivision.cc
M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/intern/mesh_extractors/extract_mesh.h
M	source/blender/editors/mesh/editmesh_utils.c
M	source/blender/editors/transform/transform_snap_object.c
M	source/blender/editors/util/ed_transverts.c
M	source/blender/makesdna/DNA_object_types.h
M	source/blender/modifiers/intern/MOD_subsurf.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 269d90b868e..1801c1ee1c9 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -399,7 +399,6 @@ bool editbmesh_modifier_is_enabled(struct Scene *scene,
 void makeDerivedMesh(struct Depsgraph *depsgraph,
                      struct Scene *scene,
                      struct Object *ob,
-                     struct BMEditMesh *em,
                      const struct CustomData_MeshMasks *dataMask);
 
 void DM_calc_loop_tangents(DerivedMesh *dm,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 5be06dcc5c3..1da7ae3da8a 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -62,14 +62,6 @@ typedef struct BMEditMesh {
   struct BMLoop *(*looptris)[3];
   int tottri;
 
-  struct Mesh *mesh_eval_final, *mesh_eval_cage;
-
-  /** Cached cage bounding box of `mesh_eval_cage` for selection. */
-  struct BoundBox *bb_cage;
-
-  /** Evaluated mesh data-mask. */
-  CustomData_MeshMasks lastDataMask;
-
   /** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */
   short selectmode;
   /** The active material (assigned to newly created faces). */
@@ -121,7 +113,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
  * don't add NULL data check here. caller must do that
  */
 BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
-void BKE_editmesh_free_derived_caches(BMEditMesh *em);
 /**
  * \note Does not free the #BMEditMesh struct itself.
  */
@@ -145,7 +136,7 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
  * If auto-smooth not already set, set it.
  */
 void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
-struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 6554a9c72aa..e1c706a82dc 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -119,6 +119,9 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
 void BKE_mesh_free_data_for_undo(struct Mesh *me);
 void BKE_mesh_clear_geometry(struct Mesh *me);
 struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
+
+void BKE_mesh_free_editmesh(struct Mesh *mesh);
+
 /**
  * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
  * (the modifier stack for example).
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index da8dba0c86b..99758f4ad78 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -530,6 +530,9 @@ struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
  */
 struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
 
+struct Mesh *BKE_object_get_editmesh_eval_final(const struct Object *object);
+struct Mesh *BKE_object_get_editmesh_eval_cage(const struct Object *object);
+
 /* Lattice accessors.
  * These functions return either the regular lattice, or the edit-mode lattice,
  * whichever is currently in use. */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 13131c24eda..d0d19ff199d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -1769,17 +1769,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
                             const CustomData_MeshMasks *dataMask,
                             const bool need_mapping)
 {
-  BLI_assert(ob->type == OB_MESH);
-
-  /* Evaluated meshes aren't supposed to be created on original instances. If you do,
-   * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
-  BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
-  BKE_object_free_derived_caches(ob);
-  if (DEG_is_active(depsgraph)) {
-    BKE_sculpt_update_object_before_eval(ob);
-  }
-
 #if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
   if (need_mapping) {
     /* Also add the flag so that it is recorded in lastDataMask. */
@@ -1846,15 +1835,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
                                  BMEditMesh *em,
                                  CustomData_MeshMasks *dataMask)
 {
-  BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
-  BKE_object_free_derived_caches(obedit);
-  if (DEG_is_active(depsgraph)) {
-    BKE_sculpt_update_object_before_eval(obedit);
-  }
-
-  BKE_editmesh_free_derived_caches(em);
-
+  Mesh *mesh = static_cast<Mesh *>(obedit->data);
   Mesh *me_cage;
   Mesh *me_final;
   GeometrySet *non_mesh_components;
@@ -1862,13 +1843,33 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
   editbmesh_calc_modifiers(
       depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
 
-  em->mesh_eval_final = me_final;
-  em->mesh_eval_cage = me_cage;
+  /* The modifier stack result is expected to share edit mesh pointer with the input.
+   * This is similar `mesh_calc_finalize()`. */
+  BKE_mesh_free_editmesh(me_final);
+  BKE_mesh_free_editmesh(me_cage);
+  me_final->edit_mesh = me_cage->edit_mesh = em;
+
+  /* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
+   * with is in edit mode).
+   * Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
+   * edit mode. */
+  if (!(obedit->mode & OB_MODE_EDIT)) {
+    BKE_mesh_wrapper_ensure_mdata(me_final);
+    if (me_final != me_cage) {
+      BKE_mesh_wrapper_ensure_mdata(me_cage);
+    }
+  }
+
+  const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
+  BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
+
+  obedit->runtime.editmesh_eval_cage = me_cage;
+
   obedit->runtime.geometry_set_eval = non_mesh_components;
 
-  BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
+  BKE_object_boundbox_calc_from_mesh(obedit, me_final);
 
-  em->lastDataMask = *dataMask;
+  obedit->runtime.last_data_mask = *dataMask;
 }
 
 static void object_get_datamask(const Depsgraph *depsgraph,
@@ -1924,9 +1925,25 @@ static void object_get_datamask(const Depsgraph *depsgraph,
 void makeDerivedMesh(struct Depsgraph *depsgraph,
                      Scene *scene,
                      Object *ob,
-                     BMEditMesh *em,
                      const CustomData_MeshMasks *dataMask)
 {
+  BLI_assert(ob->type == OB_MESH);
+
+  /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+   * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+  BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+
+  BKE_object_free_derived_caches(ob);
+  if (DEG_is_active(depsgraph)) {
+    BKE_sculpt_update_object_before_eval(ob);
+  }
+
+  /* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
+   * to the pre-evaluated state. This is because the evaluated state is not necessarily sharing the
+   * `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
+   * object mode, and then user in another scene moves object to edit mode. */
+  BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+
   bool need_mapping;
   CustomData_MeshMasks cddata_masks = *dataMask;
   object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
@@ -1965,8 +1982,9 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
       !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
       (need_mapping && !ob->runtime.last_need_mapping)) {
     CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
-    mesh_build_data(
-        depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
+
+    makeDerivedMesh(depsgraph, scene, ob, dataMask);
+
     mesh_eval = BKE_object_get_evaluated_mesh(ob);
   }
 
@@ -1981,6 +1999,15 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
                            Object *ob,
                            const CustomData_MeshMasks *dataMask)
 {
+  BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+  if (em != nullptr) {
+    /* There is no such a concept as deformed mesh in edit mode.
+     * Explicitly disallow this request so that the evaluated result is not modified with evaluated
+     * result from the wrong mode. */
+    BLI_assert_msg(0, "Request of derformed mesh of object which is in edit mode");
+    return nullptr;
+  }
+
   /* This function isn't thread-safe and can't be used during evaluation. */
   BLI_assert(DEG_is_evaluating(depsgraph) == false);
 
@@ -2055,12 +2082,12 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
    */
   object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
 
-  if (!em->mesh_eval_cage ||
-      !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
+  if (!obedit->runtime.editmesh_eval_cage ||
+      !CustomData_MeshMasks_are_matching(&(obedit->runtime.last_data_mask), &cddata_masks)) {
     editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
   }
 
-  return em->mesh_eval_cage;
+  return obedit->runtime.editmesh_eval_cage;
 }
 
 Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 6bbb9957b03..9408b9190ae 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -109,7 +109,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
   /* disable subsurf temporal, get mapped cos, and enable it */
   if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
     /* need to make new derivemesh */
-    makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH);


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list