[Bf-blender-cvs] [0562c2f31a2] undo-experiments: Merge branch 'id-ensure-unique-memory-address' into undo-experiments
Bastien Montagne
noreply at git.blender.org
Fri Feb 14 15:35:32 CET 2020
Commit: 0562c2f31a22fac9e192de47466a45de38443189
Author: Bastien Montagne
Date: Fri Feb 14 14:25:27 2020 +0100
Branches: undo-experiments
https://developer.blender.org/rB0562c2f31a22fac9e192de47466a45de38443189
Merge branch 'id-ensure-unique-memory-address' into undo-experiments
===================================================================
===================================================================
diff --cc source/blender/blenloader/intern/readfile.c
index 7240062c2dc,4231871bbb0..02423e674bd
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@@ -9806,84 -9669,6 +9815,82 @@@ static BHead *read_userdef(BlendFileDat
/** \name Read File (Internal)
* \{ */
- static int blo_undo_merge_remap_colliding_pointers_cb(void *user_data,
- ID *UNUSED(id_self),
- ID **id_pointer,
- int UNUSED(cb_flag))
++static int blo_undo_merge_remap_colliding_pointers_cb(LibraryIDLinkCallbackData *cb_data)
+{
- void **old_new_oldpointers = user_data;
++ ID **id_pointer = cb_data->id_pointer;
++ void **old_new_oldpointers = cb_data->user_data;
+ if (*id_pointer == old_new_oldpointers[0]) {
+ *id_pointer = old_new_oldpointers[1];
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+static void blo_undo_merge_and_fix_collisions_in_libmaps(FileData *fd)
+{
+ for (int i = fd->libmap->nentries; i-- > 0;) {
+ OldNew *entry = &fd->libmap->entries[i];
+ const void *oldp = entry->oldp;
+
+ OldNew *reused_entry = oldnewmap_lookup_entry(fd->libmap_undo_reused, oldp);
+ /* If both entries are pointing to same new ID of same type (stored in `nr`), there is no
+ * collision. */
+ if (reused_entry != NULL && reused_entry->newp != entry->newp &&
+ reused_entry->nr != entry->nr) {
+ const void *orig_oldp = oldp;
+ /* We have a pointer collision, find a new free oldp value.
+ * Note that we can only check libmap_undo_reused here as well, in the (rather unlikely) case
+ * we'd reach another used oldp value in a libmap item not yet processed, it will simply be
+ * detected as used/colliding too when its turn comes. */
+ for (oldp = (const char *)oldp + 1;
+ oldnewmap_lookup_entry(fd->libmap_undo_reused, oldp) != NULL;
+ oldp = (const char *)oldp + 1)
+ ;
+
+ printf(
+ "%s: found same old pointer value used by both re-used IDs and newly read-from-memfile "
+ "IDs, remapped the laters from %p to %p\n",
+ __func__,
+ orig_oldp,
+ oldp);
+ printf("%s: Nothing to worry about, unless this leads to a crash!\n", __func__);
+
+ /* Now we need to remap all orig_oldp pointers in local main to the new oldp value. */
+ /* Note that we are not using regular ID remapping API, since we only care about pointer
+ * values here, current bmain is still totally unlinked so all the extra processing would be
+ * useless - and lead to crash. */
+ Main *bmain = fd->mainlist->first;
+ ID *id;
+ const void *old_new_oldpointers[2] = {orig_oldp, oldp};
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) {
+ /* We only want to update values of old pointers in data read from memfile, not the one
+ * re-used from the old bmain. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(bmain,
+ id,
+ blo_undo_merge_remap_colliding_pointers_cb,
+ old_new_oldpointers,
+ IDWALK_NOP);
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* Inserting into libmap_undo_reused, which will be our final, merged libmap.
+ * We are doing this in that direction (and not from libmap_undo_reused to libmap) because this
+ * helps us reducing the changes to reused IDs (the fewer of their pointers we have to remap to
+ * a new address, the less likely they are to be detected as 'changed' in later undo/redo
+ * steps). */
+ oldnewmap_insert(fd->libmap_undo_reused, oldp, entry->newp, entry->nr);
+ }
+
+ /* Finally, we put our final, merged and collision-free libmap at its rightful place. */
+ oldnewmap_free(fd->libmap);
+ fd->libmap = fd->libmap_undo_reused;
+ fd->libmap_undo_reused = NULL;
+}
+
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
{
BHead *bhead = blo_bhead_first(fd);
diff --cc source/blender/editors/undo/memfile_undo.c
index a492d6fb323,a5f30409aa6..20fb99702b7
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@@ -101,93 -88,9 +101,92 @@@ static bool memfile_undosys_step_encode
return true;
}
- static int memfile_undosys_step_id_reused_cb(void *user_data,
- ID *id_self,
- ID **id_pointer,
- int UNUSED(cb_flag))
-static void memfile_undosys_step_decode(
- struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
++static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
+{
++ ID *id_self = cb_data->id_self;
++ ID **id_pointer = cb_data->id_pointer;
+ BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0);
- Main *bmain = user_data;
++ Main *bmain = cb_data->user_data;
+
+ ID *id = *id_pointer;
+ if (id != NULL && id->lib == NULL && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) {
+ bool do_stop_iter = true;
+ if (GS(id_self->name) == ID_OB) {
+ Object *ob_self = (Object *)id_self;
+ if (ob_self->type == OB_ARMATURE) {
+ if (ob_self->data == id) {
+ BLI_assert(GS(id->name) == ID_AR);
+ if (ob_self->pose != NULL) {
+ /* We have a changed/re-read armature used by an unchanged armature object: our beloved
+ * Bone pointers from the object's pose need their usual special treatment. */
+ ob_self->pose->flag |= POSE_RECALC;
+ }
+ }
+ else {
+ /* Cannot stop iteration until we checked ob_self->data pointer... */
+ do_stop_iter = false;
+ }
+ }
+ }
+
+ /* In case an old, re-used ID is using a newly read data-block (i.e. one of its ID pointers got
+ * updated), we have to tell the depsgraph about it. */
+ DEG_id_tag_update_ex(bmain, id_self, ID_RECALC_COPY_ON_WRITE);
+ return do_stop_iter ? IDWALK_RET_STOP_ITER : IDWALK_RET_NOP;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+static void memfile_undosys_step_decode(struct bContext *C,
+ struct Main *bmain,
+ UndoStep *us_p,
+ int undo_direction,
+ bool UNUSED(is_final))
{
+ BLI_assert(undo_direction != 0);
+
+ bool use_old_bmain_data = true;
+
+ if (undo_direction > 0) {
+ /* Redo case.
+ * The only time we should have to force a complete redo is when current step is tagged as a
+ * redo barrier.
+ * If previous step was not a memfile one should not matter here, current data in old bmain
+ * should still always be valid for unchanged dtat-blocks. */
+ if (us_p->use_old_bmain_data == false) {
+ use_old_bmain_data = false;
+ }
+ }
+ else {
+ /* Undo case.
+ * Here we do not care whether current step is an undo barrier, since we are comming from 'the
+ * future' we can still re-use old data. However, if *next* undo step (i.e. the one immédiately
+ * in the future, the one we are comming from) is a barrier, then we have to force a complete
+ * undo.
+ * Likewise, if next step (the one we are comming from) was a non-memfile one, there is no
+ * guarantee that current bmain data actually reflects the status of unchanged datablocks in
+ * memfile, since changes might have been flushed to current bmain data without triggering any
+ * memfile step storage (typical common case e.g. when using edit modes).
+ */
+ UndoStep *us_next = us_p->next;
+ if (us_next != NULL) {
+ if (us_next->use_old_bmain_data == false) {
+ use_old_bmain_data = false;
+ }
+ if (us_next->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ use_old_bmain_data = false;
+ }
+ }
+ }
+
+ /* Extract depsgraphs from current bmain (which may be freed during undo step reading),
+ * and store them for re-use. */
+ GHash *depsgraphs = NULL;
+ if (use_old_bmain_data) {
+ depsgraphs = BKE_scene_undo_depsgraphs_extract(bmain);
+ }
+
ED_editors_exit(bmain, false);
MemFileUndoStep *us = (MemFileUndoStep *)us_p;
More information about the Bf-blender-cvs
mailing list