[Bf-blender-cvs] [587155745b3] id-ensure-unique-memory-address: Initial rough idea of 'unique ID address' change.

Bastien Montagne noreply at git.blender.org
Tue Feb 11 17:53:58 CET 2020


Commit: 587155745b3b6c4949dd0b155abf24405b436c24
Author: Bastien Montagne
Date:   Tue Feb 11 17:50:53 2020 +0100
Branches: id-ensure-unique-memory-address
https://developer.blender.org/rB587155745b3b6c4949dd0b155abf24405b436c24

Initial rough idea of 'unique ID address' change.

Goal of this code is to ensure we only ever use a given memory address
once, for all IDs generated in a bmain.

This is crucial if we want to be able to use ID pointers instead of ID
names in undo speedup work, when re-using existing IDs.

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

M	source/blender/blenkernel/BKE_lib_id.h
M	source/blender/blenkernel/BKE_main.h
M	source/blender/blenkernel/intern/blender.c
M	source/blender/blenkernel/intern/lib_id.c
M	source/blender/blenkernel/intern/main.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/depsgraph/intern/node/deg_node_id.cc

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

diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 7d00e98f239..76360831272 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -62,7 +62,7 @@ struct PropertyRNA;
 struct bContext;
 
 size_t BKE_libblock_get_alloc_info(short type, const char **name);
-void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
+void *BKE_libblock_alloc_notest(struct Main *bmain, short type) ATTR_WARN_UNUSED_RESULT;
 void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag)
     ATTR_WARN_UNUSED_RESULT;
 void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 8b46939c6d1..03edc93ac16 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -100,6 +100,9 @@ typedef struct Main {
    */
   char is_memfile_undo_flush_needed;
 
+  struct GSet *used_id_memset;
+  short used_id_memset_tag;
+
   BlendThumbnail *blen_thumb;
 
   struct Library *curlib;
@@ -150,12 +153,23 @@ typedef struct Main {
   struct MainLock *lock;
 } Main;
 
+/* Main.used_id_memory_pointers_tag */
+enum {
+  MAIN_IDMEMSET_OWNER = 1 << 0,
+};
+
 struct Main *BKE_main_new(void);
 void BKE_main_free(struct Main *mainvar);
 
 void BKE_main_lock(struct Main *bmain);
 void BKE_main_unlock(struct Main *bmain);
 
+void BKE_main_idmemset_ensure(struct Main *bmain);
+void BKE_main_idmemset_release(struct Main *bmain);
+void BKE_main_idmemset_transfer_ownership(struct Main *bmain_dst, struct Main *bmain_src);
+void BKE_main_idmemset_usefrom(struct Main *bmain_user, struct Main *bmain_src);
+bool BKE_main_idmemset_register_id(struct Main *bmain, struct ID *id);
+
 void BKE_main_relations_create(struct Main *bmain, const short flag);
 void BKE_main_relations_free(struct Main *bmain);
 
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index ac432bf0b64..7a145f41c32 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -127,6 +127,7 @@ void BKE_blender_globals_init(void)
   U.savetime = 1;
 
   G_MAIN = BKE_main_new();
+  BKE_main_idmemset_ensure(G_MAIN);
 
   strcpy(G.ima, "//");
 
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index ce8e17c9f1d..7b57282e471 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -1204,12 +1204,22 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
  * Allocates and returns memory of the right size for the specified block type,
  * initialized to zero.
  */
-void *BKE_libblock_alloc_notest(short type)
+void *BKE_libblock_alloc_notest(Main *bmain, short type)
 {
   const char *name;
   size_t size = BKE_libblock_get_alloc_info(type, &name);
   if (size != 0) {
-    return MEM_callocN(size, name);
+    ID *id_mem = MEM_callocN(size, name);
+    if (bmain != NULL && bmain->used_id_memset != NULL) {
+      ListBase generated_ids = {.first = NULL};
+      while (UNLIKELY(!BKE_main_idmemset_register_id(bmain, id_mem))) {
+        printf("Allocating ID re-used memory address %p, trying again...", id_mem);
+        BLI_addtail(&generated_ids, id_mem);
+        id_mem = MEM_callocN(size, name);
+      }
+      BLI_freelistN(&generated_ids);
+    }
+    return id_mem;
   }
   BLI_assert(!"Request to allocate unknown data type");
   return NULL;
@@ -1225,7 +1235,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
 {
   BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
 
-  ID *id = BKE_libblock_alloc_notest(type);
+  ID *id = BKE_libblock_alloc_notest(bmain, type);
 
   if (id) {
     if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index f86e38ab2f2..74ce219862c 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -194,6 +194,8 @@ void BKE_main_free(Main *mainvar)
     BKE_main_relations_free(mainvar);
   }
 
+  BKE_main_idmemset_release(mainvar);
+
   BLI_spin_end((SpinLock *)mainvar->lock);
   MEM_freeN(mainvar->lock);
   MEM_freeN(mainvar);
@@ -209,6 +211,54 @@ void BKE_main_unlock(struct Main *bmain)
   BLI_spin_unlock((SpinLock *)bmain->lock);
 }
 
+void BKE_main_idmemset_ensure(Main *bmain)
+{
+  if (bmain->used_id_memset == NULL || (bmain->used_id_memset_tag & MAIN_IDMEMSET_OWNER) == 0) {
+    bmain->used_id_memset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+    bmain->used_id_memset_tag |= MAIN_IDMEMSET_OWNER;
+  }
+}
+
+void BKE_main_idmemset_release(Main *bmain)
+{
+  if (bmain->used_id_memset != NULL) {
+    if ((bmain->used_id_memset_tag & MAIN_IDMEMSET_OWNER) != 0) {
+      BLI_gset_free(bmain->used_id_memset, NULL);
+    }
+    bmain->used_id_memset = NULL;
+    bmain->used_id_memset_tag &= ~MAIN_IDMEMSET_OWNER;
+  }
+}
+
+void BKE_main_idmemset_transfer_ownership(Main *bmain_dst, Main *bmain_src)
+{
+  BKE_main_idmemset_release(bmain_dst);
+
+  BLI_assert(bmain_src->used_id_memset != NULL);
+  BLI_assert(bmain_src->used_id_memset_tag & MAIN_IDMEMSET_OWNER);
+
+  bmain_dst->used_id_memset = bmain_src->used_id_memset;
+  bmain_dst->used_id_memset_tag |= MAIN_IDMEMSET_OWNER;
+  bmain_src->used_id_memset_tag &= ~MAIN_IDMEMSET_OWNER;
+}
+
+void BKE_main_idmemset_usefrom(Main *bmain_user, Main *bmain_src)
+{
+  BKE_main_idmemset_release(bmain_user);
+
+  BLI_assert(bmain_src->used_id_memset != NULL);
+  bmain_user->used_id_memset = bmain_src->used_id_memset;
+}
+
+/**
+ * @return true if the ID was successfully added to the memset, false if it already existed.
+ */
+bool BKE_main_idmemset_register_id(Main *bmain, ID *id)
+{
+  BLI_assert(bmain->used_id_memset != NULL);
+  return BLI_gset_add(bmain->used_id_memset, id);
+}
+
 static int main_relations_create_idlink_cb(void *user_data,
                                            ID *id_self,
                                            ID **id_pointer,
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d9849cfa770..280ef5d585e 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -504,6 +504,8 @@ static void add_main_to_main(Main *mainvar, Main *from)
   ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
   int a;
 
+  BLI_assert(ELEM(from->used_id_memset, NULL, mainvar->used_id_memset));
+
   set_listbasepointers(mainvar, lbarray);
   a = set_listbasepointers(from, fromarray);
   while (a--) {
@@ -561,6 +563,7 @@ void blo_split_main(ListBase *mainlist, Main *main)
   int i = 0;
   for (Library *lib = main->libraries.first; lib; lib = lib->id.next, i++) {
     Main *libmain = BKE_main_new();
+    BKE_main_idmemset_usefrom(libmain, main);
     libmain->curlib = lib;
     libmain->versionfile = lib->versionfile;
     libmain->subversionfile = lib->subversionfile;
@@ -671,6 +674,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
   }
 
   m = BKE_main_new();
+  BKE_main_idmemset_usefrom(m, mainlist->first);
   BLI_addtail(mainlist, m);
 
   /* Add library data-block itself to 'main' Main, since libraries are **never** linked data.
@@ -8220,6 +8224,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
 
   /* new main */
   newmain = BKE_main_new();
+  BKE_main_idmemset_usefrom(newmain, fd->mainlist->first);
   BLI_addtail(fd->mainlist, newmain);
   newmain->curlib = lib;
 
@@ -8805,7 +8810,7 @@ static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle)
 static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag)
 {
   ListBase *lb = which_libbase(mainvar, idcode);
-  ID *ph_id = BKE_libblock_alloc_notest(idcode);
+  ID *ph_id = BKE_libblock_alloc_notest(mainvar, idcode);
 
   *((short *)ph_id->name) = idcode;
   BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
@@ -9052,6 +9057,10 @@ static BHead *read_libblock(FileData *fd,
   id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
   id->orig_id = NULL;
 
+  const bool is_id_memaddress_unique = BKE_main_idmemset_register_id(main, id);
+  /* Note: this is likely to fail at some point with current undo/redo code! */
+  BLI_assert(is_id_memaddress_unique);
+
   /* this case cannot be direct_linked: it's just the ID part */
   if (bhead->code == ID_LINK_PLACEHOLDER) {
     /* That way, we know which data-lock needs do_versions (required currently for linking). */
@@ -9660,6 +9669,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
   bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
 
   bfd->main = BKE_main_new();
+  BKE_main_idmemset_ensure(bfd->main);
   bfd->main->versionfile = fd->fileversion;
 
   bfd->type = BLENFILETYPE_BLEND;
@@ -11408,6 +11418,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
   main_newid->subversionfile = mainptr->subversionfile;
   BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
   main_newid->curlib = mainptr->curlib;
+  BKE_main_idmemset_usefrom(main_newid, mainptr);
 
   ListBase *lbarray[MAX_LIBARRAY];
   ListBase *lbarray_newid[MAX_LIBARRAY];
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 0fbf658ceb3..9bd16c8f522 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -136,7 +136,7 @@ void IDNode::init_copy_on_write(ID *id_cow_hint)
     }
   }
   else if (deg_copy_on_write_is_needed(id_orig)) {
-    id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name));
+    id_cow = (ID *)BKE_libblock_alloc_notest(NULL, GS(id_orig->name));
     DEG_COW_PRINT(
         "Create shallow copy for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
     deg_tag_copy_on_write_id(id_cow, id_orig);



More information about the Bf-blender-cvs mailing list