Optimization: pass Main to BKE_library_foreach_ID_link() and use its relations.
authorBastien Montagne <montagne29@wanadoo.fr>
Mon, 30 Jan 2017 20:41:44 +0000 (21:41 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Mon, 30 Jan 2017 21:33:20 +0000 (22:33 +0100)
Use Main->relations in BKE_library_foreach_ID_link(), when possible
(i.e. IDWALK_READONLY is set), and if the data is available of course.

This is quite minor optimization, no sensible improvements are expected,
but does not hurt either to avoid potentially tens of looping over e.g.
objects constraints and modifiers, or heap of drivers...

source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_library_query.h
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/object.c
source/blender/editors/object/object_relations.c
source/blender/python/intern/bpy_rna_id_collection.c
source/blender/windowmanager/intern/wm_operators.c

index 34035673f8850aec7a96c13b86af1c835500c2fd..72ae2cf4efa9d7a309506acdad466a9f5d101279 100644 (file)
@@ -86,7 +86,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo
 bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
 bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
 void id_sort_by_name(struct ListBase *lb, struct ID *id);
-void BKE_id_expand_local(struct ID *id);
+void BKE_id_expand_local(struct Main *bmain, struct ID *id);
 void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
 
 bool new_id(struct ListBase *lb, struct ID *id, const char *name);
index c80eb7b0760f09d68661d14ba2d4d24969435c21..693d5e9a28bbec96537012e37b66965f7edb2888 100644 (file)
@@ -80,7 +80,8 @@ enum {
 };
 
 /* Loop over all of the ID's this datablock links to. */
-void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+void BKE_library_foreach_ID_link(
+        struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
 void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
 
 int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
index 0d509ecea0635e91061895f0dd0ddc0ccda2a78a..57b707a31d3e1d8bfd4fd467c8aaa38f4f8eba65 100644 (file)
@@ -239,7 +239,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
        if (lib_local || is_local) {
                if (!is_lib) {
                        id_clear_lib_data(bmain, &brush->id);
-                       BKE_id_expand_local(&brush->id);
+                       BKE_id_expand_local(bmain, &brush->id);
 
                        /* enable fake user by default */
                        id_fake_user_set(&brush->id);
index bb426ac0279fecae7c34309573bae8b6f0a9465d..3f75bb8ec693e31604bd30447e0f16f72504827a 100644 (file)
@@ -293,9 +293,9 @@ static int id_expand_local_callback(
 /**
  * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
  */
-void BKE_id_expand_local(ID *id)
+void BKE_id_expand_local(Main *bmain, ID *id)
 {
-       BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+       BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
 }
 
 /**
@@ -304,7 +304,7 @@ void BKE_id_expand_local(ID *id)
 void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
 {
        if (ID_IS_LINKED_DATABLOCK(old_id)) {
-               BKE_id_expand_local(new_id);
+               BKE_id_expand_local(bmain, new_id);
                BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
        }
 }
@@ -331,7 +331,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
        if (lib_local || is_local) {
                if (!is_lib) {
                        id_clear_lib_data_ex(bmain, id, id_in_mainlist);
-                       BKE_id_expand_local(id);
+                       BKE_id_expand_local(bmain, id);
                }
                else {
                        ID *id_new;
@@ -1329,7 +1329,7 @@ void BKE_main_relations_create(Main *bmain)
 
        for (a = set_listbasepointers(bmain, lbarray); a--; ) {
                for (id = lbarray[a]->first; id; id = id->next) {
-                       BKE_library_foreach_ID_link(id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
+                       BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
                }
        }
 }
@@ -1777,7 +1777,7 @@ void BKE_library_make_local(
                         * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
                         * that data block local. Saves a tremendous amount of time with complex scenes... */
                        id_clear_lib_data_ex(bmain, id, true);
-                       BKE_id_expand_local(id);
+                       BKE_id_expand_local(bmain, id);
                        id->tag &= ~LIB_TAG_DOIT;
                }
                else {
index 28f66b52793ce8b2e465508116c93bdfdf997b94..03c4b80335036af5fbac8d37dfea8994eba6e912 100644 (file)
@@ -282,7 +282,7 @@ static void library_foreach_ID_as_subdata_link(
                }
        }
        else {
-               BKE_library_foreach_ID_link(id, callback, user_data, flag);
+               BKE_library_foreach_ID_link(NULL, id, callback, user_data, flag);
        }
 
        FOREACH_FINALIZE_VOID;
@@ -293,7 +293,7 @@ static void library_foreach_ID_as_subdata_link(
  *
  * \note: May be extended to be recursive in the future.
  */
-void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
+void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
 {
        LibraryForeachIDData data;
        int i;
@@ -321,10 +321,22 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
 #define CALLBACK_INVOKE(check_id_super, cb_flag) \
        FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
 
-       do {
+       for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
                data.self_id = id;
                data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
 
+               if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
+                       /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
+                        * drivers and constraints and modifiers, or material etc. with huge node tree),
+                        * but we might as well use it (Main->relations is always assumed valid, it's responsability of code
+                        * creating it to free it, especially if/when it starts modifying Main database). */
+                       MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+                       for (; entry != NULL; entry = entry->next) {
+                               FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+                       }
+                       continue;
+               }
+
                AnimData *adt = BKE_animdata_from_id(id);
                if (adt) {
                        library_foreach_animationData(&data, adt);
@@ -899,7 +911,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
                                break;
 
                }
-       } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
+       }
 
 FOREACH_FINALIZE:
        if (data.ids_handled) {
@@ -1088,7 +1100,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
        iter.curr_id = id_user;
        iter.count_direct = iter.count_indirect = 0;
 
-       BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+       BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
 
        return iter.count_direct + iter.count_indirect;
 }
@@ -1117,7 +1129,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
                        }
                        iter.curr_id = id_curr;
                        BKE_library_foreach_ID_link(
-                                   id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+                                   bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
 
                        is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
                }
@@ -1168,7 +1180,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
                                continue;
                        }
                        iter.curr_id = id_curr;
-                       BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+                       BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
 
                        is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
                }
@@ -1245,7 +1257,8 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
                                        /* Unused ID (so far), no need to check it further. */
                                        continue;
                                }
-                               BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+                               BKE_library_foreach_ID_link(
+                                           bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
                        }
                }
        }
@@ -1272,7 +1285,8 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
                                        /* Local or non-indirectly-used ID (so far), no need to check it further. */
                                        continue;
                                }
-                               BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+                               BKE_library_foreach_ID_link(
+                                           bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
                        }
                }
        }
index 5fba7b75b1e72f9146271ff6dc1ffa5211502c31..ff66c37a09b94074ff01e0983434ee545d4106f4 100644 (file)
@@ -438,7 +438,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
 #endif
                r_id_remap_data->id = id;
                libblock_remap_data_preprocess(r_id_remap_data);
-               BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+               BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
        }
        else {
                i = set_listbasepointers(bmain, lb_array);
@@ -460,7 +460,7 @@ ATTR_NONNULL(1) static void libblock_remap_data(
                                r_id_remap_data->id = id_curr;
                                libblock_remap_data_preprocess(r_id_remap_data);
                                BKE_library_foreach_ID_link(
-                                           id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+                                           NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
                        }
                }
        }
@@ -719,7 +719,7 @@ void BKE_libblock_relink_to_newid(ID *id)
        if (ID_IS_LINKED_DATABLOCK(id))
                return;
 
-       BKE_library_foreach_ID_link(id, id_relink_to_newid_looper, NULL, 0);
+       BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
 }
 
 void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
index 41f725ba2cbfd1623cb03d1bd49bc20d86b07009..09b3a7312bb991e5a2c9f836f5572b4885d31861 100644 (file)
@@ -1204,7 +1204,7 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
        if (lib_local || is_local) {
                if (!is_lib) {
                        id_clear_lib_data(bmain, &ob->id);
-                       BKE_id_expand_local(&ob->id);
+                       BKE_id_expand_local(bmain, &ob->id);
                        if (clear_proxy) {
                                if (ob->proxy_from != NULL) {
                                        ob->proxy_from->proxy = NULL;
index d30022c01f89b4d6ccdb7b6b0d8b60ec14b7cd2e..01c307fa0d225a48f791ce0a89ce85be20cf4be7 100644 (file)
@@ -2170,12 +2170,12 @@ static void tag_localizable_objects(bContext *C, const int mode)
         */
        for (Object *object = bmain->object.first; object; object = object->id.next) {
                if ((object->id.tag & LIB_TAG_DOIT) == 0) {
-                       BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
+                       BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
                }
                if (object->data) {
                        ID *data_id = (ID *) object->data;
                        if ((data_id->tag & LIB_TAG_DOIT) == 0) {
-                               BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
+                               BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
                        }
                }
        }
index 1037c83815cea07761842ee346510f8a072f3667..a7bd5afd4225c1d20ea84907573d6a6680f611ca 100644 (file)
@@ -263,7 +263,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
                        }
 
                        data_cb.id_curr = id;
-                       BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+                       BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
 
                        if (data_cb.py_id_curr) {
                                Py_DECREF(data_cb.py_id_curr);
index 36721d31ae936253da71e8639cf8f54a3b7feca7..682f4dc3b23950f692865877c5020b932e395568 100644 (file)
@@ -3948,7 +3948,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
                preview_id_data.scene = scene;
                id = (ID *)scene;
 
-               BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
+               BKE_library_foreach_ID_link(NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
        }
 
        /* Check a last time for ID not used (fake users only, in theory), and