Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <bastien@blender.org>2021-09-17 17:22:29 +0300
committerBastien Montagne <bastien@blender.org>2021-09-22 17:55:39 +0300
commit794c2828af60af02a38381c2a9a81f9046381074 (patch)
tree3c2c5c595c1c7e7f8a31598aa149ff6a4333b54c /source/blender/blenkernel/intern/main.c
parent707bcd5693aedc0c1a461bbb0ce88680e32de561 (diff)
Initial implementation of local ID re-use when appending.
This commit adds to ID struct a new optional 'weak reference' to a linked ID (in the form of a blend file library path and full ID name). This can then be used on next append to try to find a matching local ID instead of re-making the linked data local again. Ref. T90545 NOTE: ID re-use will be disabled for regular append for the time being (3.0 release), and only used for assets. Therefore, this commit should not change anything user-wise. Differential Revision: https://developer.blender.org/D12545
Diffstat (limited to 'source/blender/blenkernel/intern/main.c')
-rw-r--r--source/blender/blenkernel/intern/main.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 981f1d4a623..26dcadcc77b 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -35,6 +35,7 @@
#include "DNA_ID.h"
#include "BKE_global.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -358,6 +359,207 @@ GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
return gset;
}
+/* Utils for ID's library weak reference API. */
+typedef struct LibWeakRefKey {
+ char filepath[FILE_MAX];
+ char id_name[MAX_ID_NAME];
+} LibWeakRefKey;
+
+static LibWeakRefKey *lib_weak_key_create(LibWeakRefKey *key,
+ const char *lib_path,
+ const char *id_name)
+{
+ if (key == NULL) {
+ key = MEM_mallocN(sizeof(*key), __func__);
+ }
+ BLI_strncpy(key->filepath, lib_path, sizeof(key->filepath));
+ BLI_strncpy(key->id_name, id_name, sizeof(key->id_name));
+ return key;
+}
+
+static uint lib_weak_key_hash(const void *ptr)
+{
+ const LibWeakRefKey *string_pair = ptr;
+ uint hash = BLI_ghashutil_strhash_p_murmur(string_pair->filepath);
+ return hash ^ BLI_ghashutil_strhash_p_murmur(string_pair->id_name);
+}
+
+static bool lib_weak_key_cmp(const void *a, const void *b)
+{
+ const LibWeakRefKey *string_pair_a = a;
+ const LibWeakRefKey *string_pair_b = b;
+
+ return !(STREQ(string_pair_a->filepath, string_pair_b->filepath) &&
+ STREQ(string_pair_a->id_name, string_pair_b->id_name));
+}
+
+/**
+ * Generate a mapping between 'library path' of an ID (as a pair (relative blend file path, id
+ * name)), and a current local ID, if any.
+ *
+ * This uses the information stored in `ID.library_weak_reference`.
+ */
+GHash *BKE_main_library_weak_reference_create(Main *bmain)
+{
+ GHash *library_weak_reference_mapping = BLI_ghash_new(
+ lib_weak_key_hash, lib_weak_key_cmp, __func__);
+
+ ListBase *lb;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+ ID *id_iter = lb->first;
+ if (id_iter == NULL) {
+ continue;
+ }
+ if (!BKE_idtype_idcode_append_is_reusable(GS(id_iter->name))) {
+ continue;
+ }
+ BLI_assert(BKE_idtype_idcode_is_linkable(GS(id_iter->name)));
+
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id_iter) {
+ if (id_iter->library_weak_reference == NULL) {
+ continue;
+ }
+ LibWeakRefKey *key = lib_weak_key_create(NULL,
+ id_iter->library_weak_reference->library_filepath,
+ id_iter->library_weak_reference->library_id_name);
+ BLI_ghash_insert(library_weak_reference_mapping, key, id_iter);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ }
+ FOREACH_MAIN_LISTBASE_END;
+
+ return library_weak_reference_mapping;
+}
+
+/**
+ * Destroy the data generated by #BKE_main_library_weak_reference_create.
+ */
+void BKE_main_library_weak_reference_destroy(GHash *library_weak_reference_mapping)
+{
+ BLI_ghash_free(library_weak_reference_mapping, MEM_freeN, NULL);
+}
+
+/**
+ * Search for a local ID matching the given linked ID reference.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_relative_path: the path of a blend file library (relative to current working
+ * one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID
+ * type.
+ */
+ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_mapping,
+ const char *library_filepath,
+ const char *library_id_name)
+{
+ LibWeakRefKey key;
+ lib_weak_key_create(&key, library_filepath, library_id_name);
+ return (ID *)BLI_ghash_lookup(library_weak_reference_mapping, &key);
+}
+
+/**
+ * Add the given ID weak library reference to given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_relative_path: the path of a blend file library (relative to current working
+ * one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param new_id: New local ID matching given weak reference.
+ */
+void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapping,
+ const char *library_filepath,
+ const char *library_id_name,
+ ID *new_id)
+{
+ BLI_assert(GS(library_id_name) == GS(new_id->name));
+ BLI_assert(new_id->library_weak_reference == NULL);
+ BLI_assert(BKE_idtype_idcode_append_is_reusable(GS(new_id->name)));
+
+ new_id->library_weak_reference = MEM_mallocN(sizeof(*(new_id->library_weak_reference)),
+ __func__);
+
+ LibWeakRefKey *key = lib_weak_key_create(NULL, library_filepath, library_id_name);
+ void **id_p;
+ const bool already_exist_in_mapping = BLI_ghash_ensure_p(
+ library_weak_reference_mapping, key, &id_p);
+ BLI_assert(!already_exist_in_mapping);
+
+ BLI_strncpy(new_id->library_weak_reference->library_filepath,
+ library_filepath,
+ sizeof(new_id->library_weak_reference->library_filepath));
+ BLI_strncpy(new_id->library_weak_reference->library_id_name,
+ library_id_name,
+ sizeof(new_id->library_weak_reference->library_id_name));
+ *id_p = new_id;
+}
+
+/**
+ * Update the status of the given ID weak library reference in current local IDs and the runtime
+ * mapping.
+ *
+ * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
+ * `new_id`.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_relative_path: the path of a blend file library (relative to current working
+ * one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ * \param new_id: New local ID matching given weak reference.
+ */
+void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_mapping,
+ const char *library_filepath,
+ const char *library_id_name,
+ ID *old_id,
+ ID *new_id)
+{
+ BLI_assert(GS(library_id_name) == GS(old_id->name));
+ BLI_assert(GS(library_id_name) == GS(new_id->name));
+ BLI_assert(old_id->library_weak_reference != NULL);
+ BLI_assert(new_id->library_weak_reference == NULL);
+ BLI_assert(STREQ(old_id->library_weak_reference->library_filepath, library_filepath));
+ BLI_assert(STREQ(old_id->library_weak_reference->library_id_name, library_id_name));
+
+ LibWeakRefKey key;
+ lib_weak_key_create(&key, library_filepath, library_id_name);
+ void **id_p = BLI_ghash_lookup_p(library_weak_reference_mapping, &key);
+ BLI_assert(id_p != NULL && *id_p == old_id);
+
+ new_id->library_weak_reference = old_id->library_weak_reference;
+ old_id->library_weak_reference = NULL;
+ *id_p = new_id;
+}
+
+/**
+ * Remove the given ID weak library reference from the given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_relative_path: the path of a blend file library (relative to current working
+ * one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ */
+void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_mapping,
+ const char *library_filepath,
+ const char *library_id_name,
+ ID *old_id)
+{
+ BLI_assert(GS(library_id_name) == GS(old_id->name));
+ BLI_assert(old_id->library_weak_reference != NULL);
+
+ LibWeakRefKey key;
+ lib_weak_key_create(&key, library_filepath, library_id_name);
+
+ BLI_assert(BLI_ghash_lookup(library_weak_reference_mapping, &key) == old_id);
+ BLI_ghash_remove(library_weak_reference_mapping, &key, MEM_freeN, NULL);
+
+ MEM_SAFE_FREE(old_id->library_weak_reference);
+}
+
/**
* Generates a raw .blend file thumbnail data from given image.
*