From 53c1d15675bf6240369ee0dbdc6f06780f7b68ba Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 19 Jul 2017 15:50:49 +0200 Subject: Depsgraph: Fix particle system freeing accessing freed particle settings Need to ensure CoW IDs are freed in the right order. --- source/blender/depsgraph/intern/depsgraph.cc | 24 ++++++++++++++++++++++ .../intern/eval/deg_eval_copy_on_write.cc | 5 +++++ .../depsgraph/intern/eval/deg_eval_copy_on_write.h | 6 ++++++ source/blender/depsgraph/intern/nodes/deg_node.cc | 11 ++++++++++ source/blender/depsgraph/intern/nodes/deg_node.h | 1 + 5 files changed, 47 insertions(+) (limited to 'source') diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 1b94216d706..e1fdb2daf29 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -53,6 +53,8 @@ extern "C" { #include "DEG_depsgraph.h" +#include "intern/eval/deg_eval_copy_on_write.h" + #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" #include "intern/nodes/deg_node_operation.h" @@ -250,11 +252,13 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, /* Node Management ---------------------------- */ +#ifndef WITH_COPY_ON_WRITE static void id_node_deleter(void *value) { IDDepsNode *id_node = reinterpret_cast(value); OBJECT_GUARDED_DELETE(id_node, IDDepsNode); } +#endif TimeSourceDepsNode *Depsgraph::add_time_source() { @@ -299,7 +303,27 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name, bool do_tag) void Depsgraph::clear_id_nodes() { +#ifndef WITH_COPY_ON_WRITE BLI_ghash_clear(id_hash, NULL, id_node_deleter); +#else + /* Stupid workaround to ensure we free IDs in a proper order. */ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, id_hash) + { + if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { + continue; + } + const short id_type = GS(id_node->id_cow->name); + if (id_type != ID_PA) { + id_node->destroy(); + } + } + GHASH_FOREACH_END(); + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, id_hash) + { + OBJECT_GUARDED_DELETE(id_node, IDDepsNode); + } + GHASH_FOREACH_END(); +#endif } /* Add new relationship between two nodes. */ diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index f7e08915531..10547da2505 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -742,4 +742,9 @@ void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig) id_cow->newid = (ID *)id_orig; } +bool deg_copy_on_write_is_expanded(const struct ID *id_cow) +{ + return check_datablock_expanded(id_cow); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index c5668ed4271..4ae1de3fdbc 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -86,4 +86,10 @@ bool deg_validate_copy_on_write_datablock(ID *id_cow); /* Tag given ID block as being copy-on-wtritten. */ void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig); +/* Check whether ID datablock is expanded. + * + * TODO(sergey): Make it an inline function or a macro. + */ +bool deg_copy_on_write_is_expanded(const struct ID *id_cow); + } // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index b01fa502b36..b80d95e9076 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -191,6 +191,15 @@ void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) /* Free 'id' node. */ IDDepsNode::~IDDepsNode() { + destroy(); +} + +void IDDepsNode::destroy() +{ + if (id_orig == NULL) { + return; + } + BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free); @@ -202,6 +211,8 @@ IDDepsNode::~IDDepsNode() DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); #endif + /* Tag that the node is freed. */ + id_orig = NULL; } ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index 4e03072d486..a12a43d8658 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -139,6 +139,7 @@ struct IDDepsNode : public DepsNode { void init(const ID *id, const char *subdata); ~IDDepsNode(); + void destroy(); ComponentDepsNode *find_component(eDepsNode_Type type, const char *name = "") const; -- cgit v1.2.3