LibOverride: First stage of detection of 'need resync'.

We can fairly easily detect some resync-needed cases when applying the
overrides operations on a Pointer RNA property.

This should cover all cases where an existing override's ID pointer is
changed in its linked data.

We still have to add code to detect when a not-yet-overridden linked ID
needs to become overridden (because its relations to other data-blocks
changed in a way that requires it).

Part of T83811 & D10649.
This commit is contained in:
Bastien Montagne 2020-12-31 18:03:45 +01:00
parent 96064c3bb7
commit 534f4e90fd
4 changed files with 67 additions and 7 deletions

View File

@ -909,6 +909,8 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
ID *id_override_new = id->newid;
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
if (id_override_old != NULL) {
/* Swap the names between old override ID and new one. */
char id_name_buf[MAX_ID_NAME];
@ -1920,6 +1922,14 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
FOREACH_MAIN_ID_END;
}
static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
{
BKE_lib_id_swap(bmain, id_local, id_temp);
/* We need to keep these tags from temp ID into orig one.
* ID swap does not swap most of ID data itself. */
id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
}
/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
@ -1988,11 +1998,11 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
/* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa.
* So when we'll free tmp_id, we'll actually free old, outdated data from local. */
BKE_lib_id_swap(bmain, local, tmp_id);
lib_override_id_swap(bmain, local, tmp_id);
if (local_key != NULL && tmp_key != NULL) {
/* This is some kind of hard-coded 'always enforced override'. */
BKE_lib_id_swap(bmain, &local_key->id, &tmp_key->id);
lib_override_id_swap(bmain, &local_key->id, &tmp_key->id);
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
/* The swap of local and tmp_id inverted those pointers, we need to redefine proper
* relationships. */

View File

@ -572,6 +572,10 @@ enum {
* When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */
LIB_TAG_TEMP_MAIN = 1 << 20,
/**
* The data-block is a library override that needs re-sync to its linked reference.
*/
LIB_TAG_LIB_OVERRIDE_NEED_RESYNC = 1 << 21,
};
/* Tag given ID for an update in all the dependency graphs. */

View File

@ -61,7 +61,7 @@ static CLG_LogRef LOG = {"rna.access_compare_override"};
* Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the
* full rna path from it to given \a prop #PropertyRNA if \a rna_path is given.
*
* \note this is slightly different than 'generic' RNA 'id owner' as returned by
* \note This is slightly different than 'generic' RNA 'id owner' as returned by
* #RNA_find_real_ID_and_path, since in overrides we also consider shape keys as embedded data, not
* only root node trees and master collections.
*/
@ -104,10 +104,6 @@ static ID *rna_property_override_property_real_id_owner(Main *bmain,
}
}
if (!ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
return NULL;
}
if (r_rna_path == NULL) {
return owner_id;
}
@ -1158,6 +1154,39 @@ void RNA_struct_override_apply(Main *bmain,
ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage);
}
/* Check if an overridden ID pointer supposed to be in sync with linked data gets out of
* sync. */
if ((ptr_dst->owner_id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0 &&
op->rna_prop_type == PROP_POINTER &&
(((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag &
IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
BLI_assert(ptr_src->owner_id ==
rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL));
BLI_assert(ptr_dst->owner_id ==
rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL));
PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst);
ID *id_src = rna_property_override_property_real_id_owner(
bmain, &prop_ptr_src, NULL, NULL);
ID *id_dst = rna_property_override_property_real_id_owner(
bmain, &prop_ptr_dst, NULL, NULL);
BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src));
if (/* We might be in a case where id_dst has already been processed and its usages
* remapped to its new local override. In that case overrides and linked data are
* always properly matching. */
id_src != id_dst &&
/* If one of the pointers is NULL and not the other, or if linked reference ID of
* `id_src` is not `id_dst`, we are in a non-matching case. */
(ELEM(NULL, id_src, id_dst) || id_src->override_library->reference != id_dst)) {
ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
CLOG_INFO(
&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name);
}
}
rna_property_override_apply_ex(bmain,
&data_dst,
&data_src,

View File

@ -1238,6 +1238,8 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop
/* Used for both Pointer and Collection properties. */
static int rna_property_override_diff_propptr(Main *bmain,
ID *owner_id_a,
ID *owner_id_b,
PointerRNA *propptr_a,
PointerRNA *propptr_b,
eRNACompareMode mode,
@ -1359,6 +1361,17 @@ static int rna_property_override_diff_propptr(Main *bmain,
* override is not matching its reference anymore. */
opop->flag &= ~IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
}
else if ((owner_id_a->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0 ||
(owner_id_b->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0) {
/* In case one of the owner of the checked property is tagged as needing resync, do
* not change the 'match reference' status of its ID pointer properties overrides,
* since many non-matching ones are likely due to missing resync. */
printf(
"%s: Not checking matching ID pointer properties, since owner %s is tagged as "
"needing resync.\n",
__func__,
id_a->name);
}
else if (id_a->override_library != NULL && id_a->override_library->reference == id_b) {
opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE;
}
@ -1778,6 +1791,8 @@ int rna_property_override_diff_default(Main *bmain,
PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, rawprop_a);
PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, rawprop_b);
return rna_property_override_diff_propptr(bmain,
ptr_a->owner_id,
ptr_b->owner_id,
&propptr_a,
&propptr_b,
mode,
@ -1934,6 +1949,8 @@ int rna_property_override_diff_default(Main *bmain,
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
const int eq = rna_property_override_diff_propptr(bmain,
ptr_a->owner_id,
ptr_b->owner_id,
&iter_a.ptr,
&iter_b.ptr,
mode,