[Bf-blender-cvs] [131a758b6f8] master: Refactor BMain relations temp data.

Bastien Montagne noreply at git.blender.org
Fri Jan 22 16:06:53 CET 2021


Commit: 131a758b6f88a2be816e9351d216bcfb9c965c4b
Author: Bastien Montagne
Date:   Thu Jan 21 14:52:40 2021 +0100
Branches: master
https://developer.blender.org/rB131a758b6f88a2be816e9351d216bcfb9c965c4b

Refactor BMain relations temp data.

`bmain.relations` is used to store temp data of relations between IDs,
to speed-up some complex processes heavily relying on such information.

Previous implementation was failry unclear/confusing, and required a
not-so-nice hack to 'tag' some ID as processed.

New code changes as such:
* Using `from`/`to` naming (instead of `user`/`used`).
* More clear separation between `to` `id_pointer` and `from` one,
  using an union instead of hacking around difference between `ID *` and
  `ID **` pointers.
* Adds storage of `session_uuid` informations (mainly useful as
  debug/ensuring proper consistency of data currently).
* Adds a structure per ID in the mapping. This enables possibility of
  storing tags (and potentially more  data in the future) per-ID,
  without polluting the IDs themselves with very short-life info.

Differential Revision: https://developer.blender.org/D10164

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

M	source/blender/blenkernel/BKE_main.h
M	source/blender/blenkernel/intern/lib_id.c
M	source/blender/blenkernel/intern/lib_override.c
M	source/blender/blenkernel/intern/lib_query.c
M	source/blender/blenkernel/intern/main.c

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

diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 8106607572b..0768423fc5f 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -60,22 +60,52 @@ typedef struct BlendThumbnail {
 } BlendThumbnail;
 
 /* Structs caching relations between data-blocks in a given Main. */
+typedef struct MainIDRelationsEntryItem {
+  struct MainIDRelationsEntryItem *next;
+
+  union {
+    /* For `from_ids` list, a user of the hashed ID. */
+    struct ID *from;
+    /* For `to_ids` list, an ID used by the hashed ID. */
+    struct ID **to;
+  } id_pointer;
+  /* Session uuid of the `id_pointer`. */
+  uint session_uuid;
+
+  int usage_flag; /* Using IDWALK_ enums, defined in BKE_lib_query.h */
+} MainIDRelationsEntryItem;
+
 typedef struct MainIDRelationsEntry {
-  struct MainIDRelationsEntry *next;
-  /* WARNING! for user_to_used,
-   * that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
-  struct ID **id_pointer;
-  int usage_flag; /* Using IDWALK_ enums, in BKE_lib_query.h */
+  /* Linked list of IDs using that ID. */
+  struct MainIDRelationsEntryItem *from_ids;
+  /* Linked list of IDs used by that ID. */
+  struct MainIDRelationsEntryItem *to_ids;
+
+  /* Session uuid of the ID matching that entry. */
+  uint session_uuid;
+
+  /* Runtime tags, users should ensure those are reset after usage. */
+  uint tags;
 } MainIDRelationsEntry;
 
+/* MainIDRelationsEntry.tags */
+typedef enum MainIDRelationsEntryTags {
+  /* Generic tag marking the entry as to be processed. */
+  MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
+  /* Generic tag marking the entry as processed. */
+  MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
+} MainIDRelationsEntryTags;
+
 typedef struct MainIDRelations {
-  struct GHash *id_user_to_used;
-  struct GHash *id_used_to_user;
+  /* Mapping from an ID pointer to all of its parents (IDs using it) and children (IDs it uses).
+   * Values are `MainIDRelationsEntry` pointers. */
+  struct GHash *relations_from_pointers;
+  /* Note: we could add more mappings when needed (e.g. from session uuid?). */
 
   short flag;
 
   /* Private... */
-  struct BLI_mempool *entry_pool;
+  struct BLI_mempool *entry_items_pool;
 } MainIDRelations;
 
 enum {
@@ -172,7 +202,6 @@ void BKE_main_unlock(struct Main *bmain);
 
 void BKE_main_relations_create(struct Main *bmain, const short flag);
 void BKE_main_relations_free(struct Main *bmain);
-void BKE_main_relations_ID_remove(struct Main *bmain, struct ID *id);
 
 struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
 
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 838f3046ed0..54c2f5f5565 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -1795,32 +1795,31 @@ static void library_make_local_copying_check(ID *id,
     return; /* Already checked, nothing else to do. */
   }
 
-  MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+  MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->relations_from_pointers, id);
   BLI_gset_insert(loop_tags, id);
-  for (; entry != NULL; entry = entry->next) {
-
-    /* Used_to_user stores ID pointer, not pointer to ID pointer. */
-    ID *par_id = (ID *)entry->id_pointer;
-
+  for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+       from_id_entry = from_id_entry->next) {
     /* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
      * relation we want to check is in the other way around. */
-    if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
+    if (from_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
       continue;
     }
 
+    ID *from_id = from_id_entry->id_pointer.from;
+
     /* Shape-keys are considered 'private' to their owner ID here, and never tagged
      * (since they cannot be linked), so we have to switch effective parent to their owner.
      */
-    if (GS(par_id->name) == ID_KE) {
-      par_id = ((Key *)par_id)->from;
+    if (GS(from_id->name) == ID_KE) {
+      from_id = ((Key *)from_id)->from;
     }
 
-    if (par_id->lib == NULL) {
+    if (from_id->lib == NULL) {
       /* Local user, early out to avoid some gset querying... */
       continue;
     }
-    if (!BLI_gset_haskey(done_ids, par_id)) {
-      if (BLI_gset_haskey(loop_tags, par_id)) {
+    if (!BLI_gset_haskey(done_ids, from_id)) {
+      if (BLI_gset_haskey(loop_tags, from_id)) {
         /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
          * Note that this is the situation that can lead to archipelagoes of linked data-blocks
          * (since all of them have non-local users, they would all be duplicated,
@@ -1829,10 +1828,10 @@ static void library_make_local_copying_check(ID *id,
         continue;
       }
       /* Else, recursively check that user ID. */
-      library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+      library_make_local_copying_check(from_id, loop_tags, id_relations, done_ids);
     }
 
-    if (par_id->tag & LIB_TAG_DOIT) {
+    if (from_id->tag & LIB_TAG_DOIT) {
       /* This user will be fully local in future, so far so good,
        * nothing to do here but check next user. */
     }
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index a7e2394e7ad..388f50e12cf 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -374,9 +374,15 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
                                                  const uint missing_tag,
                                                  Library *override_group_lib_reference)
 {
-  void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
+  void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id);
   if (entry_vp == NULL) {
-    /* Already processed. */
+    /* This ID is not used by nor using any other ID. */
+    return (id->tag & tag) != 0;
+  }
+
+  MainIDRelationsEntry *entry = *entry_vp;
+  if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+    /* This ID has already been processed. */
     return (id->tag & tag) != 0;
   }
 
@@ -393,22 +399,21 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
   }
 
   /* This way we won't process again that ID, should we encounter it again through another
-   * relationship hierarchy.
-   * Note that this does not free any memory from relations, so we can still use the entries.
-   */
-  BKE_main_relations_ID_remove(bmain, id);
+   * relationship hierarchy. */
+  entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
 
-  for (MainIDRelationsEntry *entry = *entry_vp; entry != NULL; entry = entry->next) {
-    if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+  for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+       to_id_entry = to_id_entry->next) {
+    if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
       /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
        * actual dependencies. */
       continue;
     }
     /* We only consider IDs from the same library. */
-    if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
-      if (lib_override_hierarchy_recursive_tag(
-              bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
-          override_group_lib_reference == NULL) {
+    if (*to_id_entry->id_pointer.to != NULL && (*to_id_entry->id_pointer.to)->lib == id->lib) {
+      const bool needs_tag = lib_override_hierarchy_recursive_tag(
+          bmain, *to_id_entry->id_pointer.to, tag, missing_tag, override_group_lib_reference);
+      if (needs_tag && override_group_lib_reference == NULL) {
         id->tag |= tag;
       }
     }
@@ -1619,31 +1624,37 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
     return;
   }
 
-  void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root);
-  if (entry_pp == NULL) {
-    /* Already processed. */
+  void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
+  if (entry_vp == NULL) {
+    /* This ID is not used by nor using any other ID. */
+    lib_override_library_id_reset_do(bmain, id_root);
+    return;
+  }
+
+  MainIDRelationsEntry *entry = *entry_vp;
+  if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+    /* This ID has already been processed. */
     return;
   }
 
   lib_override_library_id_reset_do(bmain, id_root);
 
   /* This way we won't process again that ID, should we encounter it again through another
-   * relationship hierarchy.
-   * Note that this does not free any memory from relations, so we can still use the entries.
-   */
-  BKE_main_relations_ID_remove(bmain, id_root);
+   * relationship hierarchy. */
+  entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
 
-  for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) {
-    if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
+  for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+       to_id_entry = to_id_entry->next) {
+    if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
       /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
        * actual dependencies. */
       continue;
     }
     /* We only consider IDs from the same library. */
-    if (entry->id_pointer != NULL) {
-      ID *id_entry = *entry->id_pointer;
-      if (id_entry->override_library != NULL) {
-        lib_override_library_id_hierarchy_recursive_reset(bmain, id_entry);
+    if (*to_id_entry->id_pointer.to != NULL) {
+      ID *to_id = *to_id_entry->id_pointer.to;
+      if (to_id->override_library != NULL) {
+        lib_override_library_id_hierarchy_recursive_reset(bmain, to_id);
       }
     }
   }
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_q

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list