Changeset View
Changeset View
Standalone View
Standalone View
source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
| Show First 20 Lines • Show All 505 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Callback for BKE_library_foreach_ID_link which remaps original ID pointer | /* Callback for BKE_library_foreach_ID_link which remaps original ID pointer | ||||
| * with the one created by CoW system. */ | * with the one created by CoW system. */ | ||||
| struct RemapCallbackUserData { | struct RemapCallbackUserData { | ||||
| /* Dependency graph for which remapping is happening. */ | /* Dependency graph for which remapping is happening. */ | ||||
| const Depsgraph *depsgraph; | const Depsgraph *depsgraph; | ||||
| /* Create placeholder for ID nodes for cases when we need to remap original | |||||
| * ID to it[s CoW version but we don't have required ID node yet. | |||||
| * | |||||
| * This happens when expansion happens a ta construction time. */ | |||||
| DepsgraphNodeBuilder *node_builder; | |||||
| bool create_placeholders; | |||||
| }; | }; | ||||
| int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) | int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) | ||||
| { | { | ||||
| ID **id_p = cb_data->id_pointer; | ID **id_p = cb_data->id_pointer; | ||||
| if (*id_p == nullptr) { | if (*id_p == nullptr) { | ||||
| return IDWALK_RET_NOP; | return IDWALK_RET_NOP; | ||||
| } | } | ||||
| ID *id_self = cb_data->id_self; | |||||
| RemapCallbackUserData *user_data = (RemapCallbackUserData *)cb_data->user_data; | RemapCallbackUserData *user_data = (RemapCallbackUserData *)cb_data->user_data; | ||||
| const Depsgraph *depsgraph = user_data->depsgraph; | const Depsgraph *depsgraph = user_data->depsgraph; | ||||
| ID *id_orig = *id_p; | ID *id_orig = *id_p; | ||||
| if (deg_copy_on_write_is_needed(id_orig)) { | if (deg_copy_on_write_is_needed(id_orig)) { | ||||
| ID *id_cow; | ID *id_cow = depsgraph->get_cow_id(id_orig); | ||||
| if (user_data->create_placeholders) { | |||||
| /* Special workaround to stop creating temp datablocks for | |||||
| * objects which are coming from scene's collection and which | |||||
| * are never linked to any of layers. | |||||
| * | |||||
| * TODO(sergey): Ideally we need to tell ID looper to ignore | |||||
| * those or at least make it more reliable check where the | |||||
| * pointer is coming from. */ | |||||
| const ID_Type id_type = GS(id_orig->name); | |||||
| const ID_Type id_type_self = GS(id_self->name); | |||||
| if (id_type == ID_OB && id_type_self == ID_SCE) { | |||||
| IDNode *id_node = depsgraph->find_id_node(id_orig); | |||||
| if (id_node == nullptr) { | |||||
| id_cow = id_orig; | |||||
| } | |||||
| else { | |||||
| id_cow = id_node->id_cow; | |||||
| } | |||||
| } | |||||
| else { | |||||
| id_cow = user_data->node_builder->ensure_cow_id(id_orig); | |||||
| } | |||||
| } | |||||
| else { | |||||
| id_cow = depsgraph->get_cow_id(id_orig); | |||||
| } | |||||
| BLI_assert(id_cow != nullptr); | BLI_assert(id_cow != nullptr); | ||||
| DEG_COW_PRINT( | DEG_COW_PRINT( | ||||
| " Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); | " Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); | ||||
| *id_p = id_cow; | *id_p = id_cow; | ||||
| } | } | ||||
| return IDWALK_RET_NOP; | return IDWALK_RET_NOP; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | if (*id_p != nullptr) { | ||||
| if (!check_datablock_expanded(*id_p)) { | if (!check_datablock_expanded(*id_p)) { | ||||
| data->is_valid = false; | data->is_valid = false; | ||||
| /* TODO(sergey): Store which is not valid? */ | /* TODO(sergey): Store which is not valid? */ | ||||
| } | } | ||||
| } | } | ||||
| return IDWALK_RET_NOP; | return IDWALK_RET_NOP; | ||||
| } | } | ||||
| } // namespace | |||||
| /* Actual implementation of logic which "expands" all the data which was not | /* Actual implementation of logic which "expands" all the data which was not | ||||
| * yet copied-on-write. | * yet copied-on-write. | ||||
| * | * | ||||
| * NOTE: Expects that CoW datablock is empty. */ | * NOTE: Expects that CoW datablock is empty. */ | ||||
| ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, | ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node) | ||||
| const IDNode *id_node, | |||||
| DepsgraphNodeBuilder *node_builder, | |||||
| bool create_placeholders) | |||||
| { | { | ||||
| const ID *id_orig = id_node->id_orig; | const ID *id_orig = id_node->id_orig; | ||||
| ID *id_cow = id_node->id_cow; | ID *id_cow = id_node->id_cow; | ||||
| const int id_cow_recalc = id_cow->recalc; | const int id_cow_recalc = id_cow->recalc; | ||||
| /* No need to expand such datablocks, their copied ID is same as original | /* No need to expand such datablocks, their copied ID is same as original | ||||
| * one already. */ | * one already. */ | ||||
| if (!deg_copy_on_write_is_needed(id_orig)) { | if (!deg_copy_on_write_is_needed(id_orig)) { | ||||
| return id_cow; | return id_cow; | ||||
| } | } | ||||
| DEG_COW_PRINT( | DEG_COW_PRINT( | ||||
| "Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); | "Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); | ||||
| /* Sanity checks. */ | /* Sanity checks. */ | ||||
| /* NOTE: Disabled for now, conflicts when re-using evaluated datablock when | BLI_assert(check_datablock_expanded(id_cow) == false); | ||||
| * rebuilding dependencies. */ | |||||
| if (check_datablock_expanded(id_cow) && create_placeholders) { | |||||
| deg_free_copy_on_write_datablock(id_cow); | |||||
| } | |||||
| // BLI_assert(check_datablock_expanded(id_cow) == false); | |||||
| /* Copy data from original ID to a copied version. */ | /* Copy data from original ID to a copied version. */ | ||||
| /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference | /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference | ||||
| * original geometry arrays for until those are modified. */ | * original geometry arrays for until those are modified. */ | ||||
| /* TODO(sergey): We do some trickery with temp bmain and extra ID pointer | /* TODO(sergey): We do some trickery with temp bmain and extra ID pointer | ||||
| * just to be able to use existing API. Ideally we need to replace this with | * just to be able to use existing API. Ideally we need to replace this with | ||||
| * in-place copy from existing datablock to a prepared memory. | * in-place copy from existing datablock to a prepared memory. | ||||
| * | * | ||||
| * NOTE: We don't use BKE_main_{new,free} because: | * NOTE: We don't use BKE_main_{new,free} because: | ||||
| Show All 36 Lines | #ifdef NESTED_ID_NASTY_WORKAROUND | ||||
| ntree_hack_remap_pointers(depsgraph, id_cow); | ntree_hack_remap_pointers(depsgraph, id_cow); | ||||
| #endif | #endif | ||||
| /* Do it now, so remapping will understand that possibly remapped self ID | /* Do it now, so remapping will understand that possibly remapped self ID | ||||
| * is not to be remapped again. */ | * is not to be remapped again. */ | ||||
| deg_tag_copy_on_write_id(id_cow, id_orig); | deg_tag_copy_on_write_id(id_cow, id_orig); | ||||
| /* Perform remapping of the nodes. */ | /* Perform remapping of the nodes. */ | ||||
| RemapCallbackUserData user_data = {nullptr}; | RemapCallbackUserData user_data = {nullptr}; | ||||
| user_data.depsgraph = depsgraph; | user_data.depsgraph = depsgraph; | ||||
| user_data.node_builder = node_builder; | |||||
| user_data.create_placeholders = create_placeholders; | |||||
| BKE_library_foreach_ID_link(nullptr, | BKE_library_foreach_ID_link(nullptr, | ||||
| id_cow, | id_cow, | ||||
| foreach_libblock_remap_callback, | foreach_libblock_remap_callback, | ||||
| (void *)&user_data, | (void *)&user_data, | ||||
| IDWALK_IGNORE_EMBEDDED_ID); | IDWALK_IGNORE_EMBEDDED_ID); | ||||
| /* Correct or tweak some pointers which are not taken care by foreach | /* Correct or tweak some pointers which are not taken care by foreach | ||||
| * from above. */ | * from above. */ | ||||
| update_id_after_copy(depsgraph, id_node, id_orig, id_cow); | update_id_after_copy(depsgraph, id_node, id_orig, id_cow); | ||||
| id_cow->recalc = id_cow_recalc; | id_cow->recalc = id_cow_recalc; | ||||
| return id_cow; | return id_cow; | ||||
| } | } | ||||
| /* NOTE: Depsgraph is supposed to have ID node already. */ | } // namespace | ||||
| ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, | |||||
| ID *id_orig, | |||||
| DepsgraphNodeBuilder *node_builder, | |||||
| bool create_placeholders) | |||||
| { | |||||
| IDNode *id_node = depsgraph->find_id_node(id_orig); | |||||
| BLI_assert(id_node != nullptr); | |||||
| return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders); | |||||
| } | |||||
| ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node) | ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node) | ||||
| { | { | ||||
| const ID *id_orig = id_node->id_orig; | const ID *id_orig = id_node->id_orig; | ||||
| ID *id_cow = id_node->id_cow; | ID *id_cow = id_node->id_cow; | ||||
| /* Similar to expansion, no need to do anything here. */ | /* Similar to expansion, no need to do anything here. */ | ||||
| if (!deg_copy_on_write_is_needed(id_orig)) { | if (!deg_copy_on_write_is_needed(id_orig)) { | ||||
| return id_cow; | return id_cow; | ||||
| ▲ Show 20 Lines • Show All 176 Lines • Show Last 20 Lines | |||||