diff options
Diffstat (limited to 'source/blender/blenkernel/intern/lib_override.c')
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.c | 215 |
1 files changed, 156 insertions, 59 deletions
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d6f037f64a4..457d096f983 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -27,11 +27,15 @@ #include "MEM_guardedalloc.h" #include "DNA_ID.h" +#include "DNA_key_types.h" #include "DNA_object_types.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "BKE_armature.h" +#include "BKE_idtype.h" +#include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" @@ -40,6 +44,7 @@ #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "RNA_access.h" @@ -113,7 +118,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id) /** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy) { - BLI_assert(src_id->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id)); if (dst_id->override_library != NULL) { if (src_id->override_library == NULL) { @@ -125,6 +130,7 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f } } else if (src_id->override_library == NULL) { + /* Virtual overrides of embedded data does not require any extra work. */ return; } else { @@ -198,6 +204,16 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id) BKE_lib_override_library_init(local_id, reference_id); + /* Note: From liboverride perspective (and RNA one), shape keys are considered as local embedded + * data-blocks, just like root node trees or master collections. Therefore, we never need to + * create overrides for them. We need a way to mark them as overrides though. */ + Key *reference_key; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + Key *local_key = BKE_key_from_id(local_id); + BLI_assert(local_key != NULL); + local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE; + } + return local_id; } @@ -212,6 +228,12 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, ID *local_id = lib_override_library_create_from(bmain, reference_id); if (do_tagged_remap) { + Key *reference_key, *local_key = NULL; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + local_key = BKE_key_from_id(local_id); + BLI_assert(local_key != NULL); + } + ID *other_id; FOREACH_MAIN_ID_BEGIN (bmain, other_id) { if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { @@ -222,6 +244,13 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + if (reference_key != NULL) { + BKE_libblock_relink_ex(bmain, + other_id, + &reference_key->id, + &local_key->id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + } } } FOREACH_MAIN_ID_END; @@ -246,14 +275,15 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, bool BKE_lib_override_library_create_from_tag(Main *bmain) { ID *reference_id; - bool ret = true; + bool success = true; ListBase todo_ids = {NULL}; LinkData *todo_id_iter; /* Get all IDs we want to override. */ FOREACH_MAIN_ID_BEGIN (bmain, reference_id) { - if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && + BKE_idtype_idcode_is_linkable(GS(reference_id->name))) { todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__); todo_id_iter->data = reference_id; BLI_addtail(&todo_ids, todo_id_iter); @@ -265,44 +295,77 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { reference_id = todo_id_iter->data; if ((reference_id->newid = lib_override_library_create_from(bmain, reference_id)) == NULL) { - ret = false; + success = false; + break; } - else { + /* We also tag the new IDs so that in next step we can remap their pointers too. */ + reference_id->newid->tag |= LIB_TAG_DOIT; + + Key *reference_key; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + reference_key->id.tag |= LIB_TAG_DOIT; + + Key *local_key = BKE_key_from_id(reference_id->newid); + BLI_assert(local_key != NULL); + reference_key->id.newid = &local_key->id; /* We also tag the new IDs so that in next step we can remap their pointers too. */ - reference_id->newid->tag |= LIB_TAG_DOIT; + local_key->id.tag |= LIB_TAG_DOIT; } } /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole * existing linked IDs usages. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - ID *other_id; - reference_id = todo_id_iter->data; + if (success) { + for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { + ID *other_id; + reference_id = todo_id_iter->data; + ID *local_id = reference_id->newid; + + if (local_id == NULL) { + continue; + } - if (reference_id->newid == NULL) { - continue; - } + Key *reference_key, *local_key = NULL; + if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + local_key = BKE_key_from_id(reference_id->newid); + BLI_assert(local_key != NULL); + } - /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped - * to use newly created overriding IDs, if needed. */ - FOREACH_MAIN_ID_BEGIN (bmain, other_id) { - if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { - ID *local_id = reference_id->newid; - /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap - * local IDs usages anyway... */ - BKE_libblock_relink_ex(bmain, - other_id, - reference_id, - local_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + /* Still checking the whole Main, that way we can tag other local IDs as needing to be + * remapped to use newly created overriding IDs, if needed. */ + FOREACH_MAIN_ID_BEGIN (bmain, other_id) { + if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) { + /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap + * local IDs usages anyway... */ + BKE_libblock_relink_ex(bmain, + other_id, + reference_id, + local_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + if (reference_key != NULL) { + BKE_libblock_relink_ex(bmain, + other_id, + &reference_key->id, + &local_key->id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + } + } } + FOREACH_MAIN_ID_END; + } + } + else { + /* We need to cleanup potentially already created data. */ + for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { + reference_id = todo_id_iter->data; + BKE_id_delete(bmain, reference_id->newid); + reference_id->newid = NULL; } - FOREACH_MAIN_ID_END; } BLI_freelistN(&todo_ids); - return ret; + return success; } /* We only build override GHash on request. */ @@ -310,7 +373,8 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure( IDOverrideLibrary *override) { if (override->runtime == NULL) { - override->runtime = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); + override->runtime = BLI_ghash_new( + BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__); for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) { BLI_ghash_insert(override->runtime, op->rna_path, op); } @@ -469,7 +533,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; } - /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ + /* index == -1 means all indices, that is valid fallback in case we requested specific index. + */ if (!strict && (subitem_locindex != subitem_defindex) && (opop = BLI_listbase_bytes_find( &override_property->operations, @@ -617,7 +682,7 @@ bool BKE_lib_override_library_property_operation_operands_validate( * \return true if status is OK, false otherwise. */ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); ID *reference = local->override_library->reference; @@ -649,6 +714,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, @@ -672,7 +738,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) * \return true if status is OK, false otherwise. */ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); ID *reference = local->override_library->reference; @@ -712,6 +778,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) { @@ -735,9 +802,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) * Generating diff values and applying overrides are much cheaper. * * \return true if new overriding op was created, or some local data was reset. */ -bool BKE_lib_override_library_operations_create(Main *bmain, - ID *local, - const bool UNUSED(force_auto)) +bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) { BLI_assert(local->override_library != NULL); const bool is_template = (local->override_library->reference == NULL); @@ -752,9 +817,9 @@ bool BKE_lib_override_library_operations_create(Main *bmain, } if (GS(local->name) == ID_OB) { - /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure - * this is valid, but in some situations (like hidden collections etc.) this won't be the - * case, so we need to take care of this ourselves. */ + /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would + * ensure this is valid, but in some situations (like hidden collections etc.) this won't + * be the case, so we need to take care of this ourselves. */ Object *ob_local = (Object *)local; if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL && ob_local->pose->flag & POSE_RECALC) { @@ -771,6 +836,7 @@ bool BKE_lib_override_library_operations_create(Main *bmain, &rnaptr_local, &rnaptr_reference, NULL, + 0, local->override_library, RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags); @@ -792,29 +858,51 @@ bool BKE_lib_override_library_operations_create(Main *bmain, return ret; } +static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata) +{ + Main *bmain = BLI_task_pool_user_data(pool); + ID *id = taskdata; + + BKE_lib_override_library_operations_create(bmain, id); +} + /** Check all overrides from given \a bmain and create/update overriding operations as needed. */ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto) { ID *id; +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(BKE_lib_override_library_main_operations_create); +#endif + /* When force-auto is set, we also remove all unused existing override properties & operations. */ if (force_auto) { BKE_lib_override_library_main_tag(bmain, IDOVERRIDE_LIBRARY_TAG_UNUSED, true); } + TaskPool *task_pool = BLI_task_pool_create(bmain, TASK_PRIORITY_HIGH); + FOREACH_MAIN_ID_BEGIN (bmain, id) { - if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) || + if ((ID_IS_OVERRIDE_LIBRARY_REAL(id) && force_auto) || (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH)) { - BKE_lib_override_library_operations_create(bmain, id, force_auto); + BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL); id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH; } } FOREACH_MAIN_ID_END; + BLI_task_pool_work_and_wait(task_pool); + + BLI_task_pool_free(task_pool); + if (force_auto) { BKE_lib_override_library_main_unused_cleanup(bmain); } + +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(BKE_lib_override_library_main_operations_create); +#endif } /** Set or clear given tag in all operations as unused in that override property data. */ @@ -869,7 +957,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons /** Remove all tagged-as-unused properties and operations from that ID override data. */ void BKE_lib_override_library_id_unused_cleanup(struct ID *local) { - if (local->override_library != NULL) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) { LISTBASE_FOREACH_MUTABLE ( IDOverrideLibraryProperty *, op, &local->override_library->properties) { if (op->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) { @@ -902,7 +990,7 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain) /** Update given override from its reference (re-applying overridden properties). */ void BKE_lib_override_library_update(Main *bmain, ID *local) { - if (local->override_library == NULL || local->override_library->reference == NULL) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) { return; } @@ -924,8 +1012,8 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) * So we work on temp copy of reference, and 'swap' its content with local. */ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! - * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will - * do, as inn-efficient as it is. :/ + * However, this is whole bunch of code work in itself, so for now plain stupid ID copy + * will do, as inn-efficient as it is. :/ * Actually, maybe not! Since we are swapping with original ID's local content, we want to * keep user-count in correct state when freeing tmp_id * (and that user-counts of IDs used by 'new' local data also remain correct). */ @@ -942,11 +1030,21 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) } /* This ID name is problematic, since it is an 'rna name property' it should not be editable or - * different from reference linked ID. But local ID names need to be unique in a given type list - * of Main, so we cannot always keep it identical, which is why we need this special manual - * handling here. */ + * different from reference linked ID. But local ID names need to be unique in a given type + * list of Main, so we cannot always keep it identical, which is why we need this special + * manual handling here. */ BLI_strncpy(tmp_id->name, local->name, sizeof(tmp_id->name)); + /* Those ugly loopback pointers again... Luckily we only need to deal with the shape keys here, + * collections' parents are fully runtime and reconstructed later. */ + Key *local_key = BKE_key_from_id(local); + Key *tmp_key = BKE_key_from_id(tmp_id); + if (local_key != NULL && tmp_key != NULL) { + /* This is some kind of hard-coded 'always enforced override'... */ + tmp_key->from = local_key->from; + tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE); + } + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; RNA_id_pointer_create(local, &rnaptr_src); RNA_id_pointer_create(tmp_id, &rnaptr_dst); @@ -978,9 +1076,9 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK; /* Full rebuild of Depsgraph! */ - - /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ - DEG_on_visible_update(bmain, true); + /* Note: this is really brute force, in theory updates from RNA should have handle this already, + * but for now let's play it safe. */ + DEG_relations_tag_update(bmain); } /** Update all overrides from given \a bmain. */ @@ -1028,17 +1126,16 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, OverrideLibraryStorage *override_storage, ID *local) { - BLI_assert(local->override_library != NULL); - BLI_assert(override_storage != NULL); - const bool is_template = (local->override_library->reference == NULL); - - if (is_template) { + if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) { /* This is actually purely local data with an override template, nothing to do here! */ return NULL; } + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); + BLI_assert(override_storage != NULL); + /* Forcefully ensure we know about all needed override operations. */ - BKE_lib_override_library_operations_create(bmain, local, false); + BKE_lib_override_library_operations_create(bmain, local); ID *storage_id; #ifdef DEBUG_OVERRIDE_TIMEIT @@ -1046,8 +1143,8 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, #endif /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy - * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib reference-counting - * completely (shallow copy...). */ + * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib + * reference-counting completely (shallow copy...). */ /* This would imply change in handling of user-count all over RNA * (and possibly all over Blender code). * Not impossible to do, but would rather see first is extra useless usual user handling is @@ -1080,7 +1177,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, void BKE_lib_override_library_operations_store_end( OverrideLibraryStorage *UNUSED(override_storage), ID *local) { - BLI_assert(local->override_library != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); /* Nothing else to do here really, we need to keep all temp override storage data-blocks in * memory until whole file is written anyway (otherwise we'd get mem pointers overlap...). */ @@ -1089,8 +1186,8 @@ void BKE_lib_override_library_operations_store_end( void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage) { - /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' - * copies of IDs without increasing usercount of used data-blocks. */ + /* We cannot just call BKE_main_free(override_storage), not until we have option to make + * 'ghost' copies of IDs without increasing usercount of used data-blocks. */ ID *id; FOREACH_MAIN_ID_BEGIN (override_storage, id) { |