Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c117
-rw-r--r--source/blender/blenkernel/intern/mesh.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c17
-rw-r--r--source/blender/blenkernel/intern/object.c18
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h6
-rw-r--r--source/blender/makesdna/DNA_object_types.h4
6 files changed, 125 insertions, 39 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 615a68dc176..dce8f348704 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -1097,6 +1097,30 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
}
}
+/* Does final touches to the final evaluated mesh, making sure it is perfectly usable.
+ *
+ * This is needed because certain information is not passed along intermediate meshes allocated
+ * during stack evaluation.
+ */
+static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
+{
+ /* Make sure the name is the same. This is because mesh allocation from template does not
+ * take care of naming. */
+ BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name));
+ /* Make sure materials are preserved from the input. */
+ if (mesh_eval->mat != NULL) {
+ MEM_freeN(mesh_eval->mat);
+ }
+ mesh_eval->mat = MEM_dupallocN(mesh_input->mat);
+ mesh_eval->totcol = mesh_input->totcol;
+ /* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
+ mesh_eval->edit_mesh = mesh_input->edit_mesh;
+ /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a
+ * template. */
+ mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH);
+ mesh_eval->smoothresh = mesh_input->smoothresh;
+}
+
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -1514,7 +1538,12 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* need to apply these back onto the Mesh. If we have no
* Mesh then we need to build one. */
if (mesh_final == NULL) {
- mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ if (deformed_verts == NULL) {
+ mesh_final = mesh_input;
+ }
+ else {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ }
}
if (deformed_verts) {
BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
@@ -1522,9 +1551,17 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
deformed_verts = NULL;
}
+ /* Denotes whether the object which the modifier stack came from owns the mesh or whether the
+ * mesh is shared across multiple objects since there are no effective modifiers. */
+ const bool is_own_mesh = (mesh_final != mesh_input);
+
/* Add orco coordinates to final and deformed mesh if requested. */
if (dataMask->vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+ /* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case
+ * matches input mesh. */
+ if (is_own_mesh) {
+ add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+ }
if (mesh_deform) {
add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO);
@@ -1539,7 +1576,28 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
/* Compute normals. */
- mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final);
+ if (is_own_mesh) {
+ mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final);
+ }
+ else {
+ Mesh_Runtime *runtime = &mesh_input->runtime;
+ if (runtime->mesh_eval == NULL) {
+ BLI_assert(runtime->eval_mutex != NULL);
+ BLI_mutex_lock(runtime->eval_mutex);
+ if (runtime->mesh_eval == NULL) {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final);
+ mesh_calc_finalize(mesh_input, mesh_final);
+ runtime->mesh_eval = mesh_final;
+ }
+ BLI_mutex_unlock(runtime->eval_mutex);
+ }
+ mesh_final = runtime->mesh_eval;
+ }
+
+ if (is_own_mesh) {
+ mesh_calc_finalize(mesh_input, mesh_final);
+ }
/* Return final mesh */
*r_final = mesh_final;
@@ -1915,40 +1973,29 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
-static void mesh_finalize_eval(Object *object)
+static void assign_object_mesh_eval(Object *object)
{
+ BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
+
Mesh *mesh = (Mesh *)object->data;
Mesh *mesh_eval = object->runtime.mesh_eval;
- /* Special Tweaks for cases when evaluated mesh came from
- * BKE_mesh_new_nomain_from_template().
- */
- BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
- if (mesh_eval->mat != NULL) {
- MEM_freeN(mesh_eval->mat);
+
+ /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result
+ * is not guaranteed to be owned by object.
+ *
+ * Check ownership now, since later on we can not go to a mesh owned by someone else via object's
+ * runtime: this could cause access freed data on depsgraph destruction (mesh who owns the final
+ * result might be freed prior to object). */
+ if (mesh_eval == mesh->runtime.mesh_eval) {
+ object->runtime.is_mesh_eval_owned = false;
+ }
+ else {
+ mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ object->runtime.is_mesh_eval_owned = true;
}
- /* Set flag which makes it easier to see what's going on in a debugger. */
- mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
- mesh_eval->mat = MEM_dupallocN(mesh->mat);
- mesh_eval->totcol = mesh->totcol;
- /* Make evaluated mesh to share same edit mesh pointer as original
- * and copied meshes.
- */
- mesh_eval->edit_mesh = mesh->edit_mesh;
- /* Copy autosmooth settings from original mesh.
- * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
- * extra care here.
- */
- mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
- mesh_eval->smoothresh = mesh->smoothresh;
- /* Replace evaluated object's data with fully evaluated mesh. */
- /* TODO(sergey): There was statement done by Sybren and Mai that this
- * caused modifiers to be applied twice. which is weirtd and shouldn't
- * really happen. But since there is no reference to the report, can not
- * do much about this.
- */
- /* Object is sometimes not evaluated!
- * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
+ /* NOTE: We are not supposed to invoke evaluation for original object, but some areas are still
+ * under process of being ported, so we play safe here. */
if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
object->data = mesh_eval;
}
@@ -2016,7 +2063,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
}
- mesh_finalize_eval(ob);
+ assign_object_mesh_eval(ob);
ob->runtime.last_data_mask = *dataMask;
ob->runtime.last_need_mapping = need_mapping;
@@ -2032,7 +2079,9 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
#endif
}
- mesh_runtime_check_normals_valid(ob->runtime.mesh_eval);
+ if (ob->runtime.mesh_eval != NULL) {
+ mesh_runtime_check_normals_valid(ob->runtime.mesh_eval);
+ }
mesh_build_extra_data(depsgraph, ob);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 56832c1724a..aa13950f0d5 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -522,6 +522,8 @@ void BKE_mesh_init(Mesh *me)
CustomData_reset(&me->fdata);
CustomData_reset(&me->pdata);
CustomData_reset(&me->ldata);
+
+ BKE_mesh_runtime_reset(me);
}
Mesh *BKE_mesh_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 06abd80b86f..4c3761c7ffc 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -33,6 +33,7 @@
#include "BLI_threads.h"
#include "BKE_bvhutils.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_subdiv_ccg.h"
@@ -50,6 +51,8 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
void BKE_mesh_runtime_reset(Mesh *mesh)
{
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+ mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
+ BLI_mutex_init(mesh->runtime.eval_mutex);
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -59,16 +62,30 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
Mesh_Runtime *runtime = &mesh->runtime;
+ runtime->mesh_eval = NULL;
runtime->edit_data = NULL;
runtime->batch_cache = NULL;
runtime->subdiv_ccg = NULL;
memset(&runtime->looptris, 0, sizeof(runtime->looptris));
runtime->bvh_cache = NULL;
runtime->shrinkwrap_data = NULL;
+
+ mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
+ BLI_mutex_init(mesh->runtime.eval_mutex);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
+ if (mesh->runtime.eval_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.eval_mutex);
+ MEM_freeN(mesh->runtime.eval_mutex);
+ mesh->runtime.eval_mutex = NULL;
+ }
+ if (mesh->runtime.mesh_eval != NULL) {
+ mesh->runtime.mesh_eval->edit_mesh = NULL;
+ BKE_id_free(NULL, mesh->runtime.mesh_eval);
+ mesh->runtime.mesh_eval = NULL;
+ }
BKE_mesh_runtime_clear_geometry(mesh);
BKE_mesh_batch_cache_free(mesh);
BKE_mesh_runtime_clear_edit_data(mesh);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a4dbbb5d238..675239244a8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -361,6 +361,13 @@ static void object_update_from_subsurf_ccg(Object *object)
if (object->type != OB_MESH) {
return;
}
+ /* If object does not own evaluated mesh we can not access it since it might be freed already
+ * (happens on dependency graph free where order of CoW-ed IDs free is undefined).
+ *
+ * Good news is: such mesh does not have modifiers applied, so no need to worry about CCG. */
+ if (!object->runtime.is_mesh_eval_owned) {
+ return;
+ }
/* Object was never evaluated, so can not have CCG subdivision surface. */
Mesh *mesh_eval = object->runtime.mesh_eval;
if (mesh_eval == NULL) {
@@ -448,12 +455,13 @@ void BKE_object_free_derived_caches(Object *ob)
object_update_from_subsurf_ccg(ob);
BKE_object_free_derived_mesh_caches(ob);
- if (ob->runtime.mesh_eval != NULL) {
+ /* Restore initial pointer. */
+ if (ob->runtime.mesh_orig != NULL) {
+ ob->data = ob->runtime.mesh_orig;
+ }
+
+ if ((ob->runtime.mesh_eval != NULL && ob->runtime.is_mesh_eval_owned)) {
Mesh *mesh_eval = ob->runtime.mesh_eval;
- /* Restore initial pointer. */
- if (ob->data == mesh_eval) {
- ob->data = ob->runtime.mesh_orig;
- }
/* Evaluated mesh points to edit mesh, but does not own it. */
mesh_eval->edit_mesh = NULL;
BKE_mesh_free(mesh_eval);
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index f54c178f1d0..8a9a69ac178 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -75,6 +75,12 @@ struct MLoopTri_Store {
/* not saved in file! */
typedef struct Mesh_Runtime {
+ /* Evaluated mesh for objects which do not have effective modifiers. This mesh is sued as a
+ * result of modifier stack evaluation.
+ * Since modifier stack evaluation is threaded on object level we need some synchronization. */
+ struct Mesh *mesh_eval;
+ void *eval_mutex;
+
struct EditMeshData *edit_data;
void *batch_cache;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 9bbb6f1656c..e248d60b69b 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -155,6 +155,10 @@ typedef struct Object_Runtime {
* It has all modifiers applied.
*/
struct Mesh *mesh_eval;
+ /* Denotes whether the evaluated mesh is ownbed by this object or is referenced and owned by
+ * somebody else. */
+ int is_mesh_eval_owned;
+ int _pad3[3];
/**
* Mesh structure created during object evaluation.
* It has deforemation only modifiers applied on it.