Fix T102766: Refactor liboverride diffing, by un-threading restoration step.

The reported backtrace in T102766 strongly points at some
concurrency issues within exisitng liboverride diffing code that
restores forbidden changes to reference linked data values.

This commit instead add tags to mark liboverrides/properties that need
to be restored, and do so in a separate new step of diffing, from the
main thread only.
This commit is contained in:
Bastien Montagne 2022-12-25 23:23:40 +09:00
parent 0bf8b98437
commit d05909a70c
Notes: blender-bot 2023-02-14 07:36:17 +01:00
Referenced by commit a6b6f5db10, Fix issue with recent refactor in liboverride diffing.
Referenced by issue #102766, Crash when editing geometry node tree or curves in the graph editor
5 changed files with 311 additions and 155 deletions

View File

@ -410,8 +410,6 @@ bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct
* \note This is by far the biggest operation (the more time-consuming) of the three so far,
* since it has to go over all properties in depth (all overridable ones at least).
* Generating differential values and applying overrides are much cheaper.
*
* \return true if any library operation was created.
*/
void BKE_lib_override_library_operations_create(struct Main *bmain,
struct ID *local,
@ -425,6 +423,29 @@ void BKE_lib_override_library_main_operations_create(struct Main *bmain,
bool force_auto,
int *r_report_flags);
/**
* Restore forbidden modified override properties to the values of their matching properties in the
* linked reference ID.
*
* \param r_report_flags #eRNAOverrideMatchResult flags giving info about the result of this call.
*
* \note Typically used as part of BKE_lib_override_library_main_operations_create process, since
* modifying RNA properties from non-main threads is not safe.
*/
void BKE_lib_override_library_operations_restore(struct Main *bmain,
struct ID *local,
int *r_report_flags);
/**
* Restore forbidden modified override properties to the values of their matching properties in the
* linked reference ID, for all liboverride IDs tagged as needing such process in given `bmain`.
*
* \param r_report_flags #eRNAOverrideMatchResult flags giving info about the result of this call.
*
* \note Typically used as part of BKE_lib_override_library_main_operations_create process, since
* modifying RNA properties from non-main threads is not safe.
*/
void BKE_lib_override_library_main_operations_restore(struct Main *bmain, int *r_report_flags);
/**
* Reset all overrides in given \a id_root, while preserving ID relations.
*

View File

@ -3297,7 +3297,10 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
return true;
}
void BKE_lib_override_library_operations_create(Main *bmain, ID *local, int *r_report_flags)
static void lib_override_library_operations_create(Main *bmain,
ID *local,
const eRNAOverrideMatch override_match_flags,
eRNAOverrideMatchResult *r_report_flags)
{
BLI_assert(!ID_IS_LINKED(local));
BLI_assert(local->override_library != nullptr);
@ -3330,19 +3333,24 @@ void BKE_lib_override_library_operations_create(Main *bmain, ID *local, int *r_r
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
eRNAOverrideMatchResult local_report_flags = RNA_OVERRIDE_MATCH_RESULT_INIT;
RNA_struct_override_matches(
bmain,
&rnaptr_local,
&rnaptr_reference,
nullptr,
0,
local->override_library,
(eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE),
&local_report_flags);
RNA_struct_override_matches(bmain,
&rnaptr_local,
&rnaptr_reference,
nullptr,
0,
local->override_library,
override_match_flags,
&local_report_flags);
if (local_report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
CLOG_INFO(&LOG, 2, "We did restore some properties of %s from its reference", local->name);
}
if (local_report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED) {
CLOG_INFO(&LOG,
2,
"We did tag some properties of %s for restoration from its reference",
local->name);
}
if (local_report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
CLOG_INFO(&LOG, 2, "We did generate library override rules for %s", local->name);
}
@ -3351,10 +3359,50 @@ void BKE_lib_override_library_operations_create(Main *bmain, ID *local, int *r_r
}
if (r_report_flags != nullptr) {
*r_report_flags |= local_report_flags;
*r_report_flags = static_cast<eRNAOverrideMatchResult>(*r_report_flags | local_report_flags);
}
}
}
void BKE_lib_override_library_operations_create(Main *bmain, ID *local, int *r_report_flags)
{
lib_override_library_operations_create(
bmain,
local,
static_cast<eRNAOverrideMatch>(RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE),
reinterpret_cast<eRNAOverrideMatchResult *>(r_report_flags));
}
void BKE_lib_override_library_operations_restore(Main *bmain, ID *local, int *r_report_flags)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(local) || (local->override_library->runtime->tag &
IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RESTORE) == 0) {
return;
}
PointerRNA rnaptr_src, rnaptr_dst;
RNA_id_pointer_create(local, &rnaptr_dst);
RNA_id_pointer_create(local->override_library->reference, &rnaptr_src);
RNA_struct_override_apply(
bmain,
&rnaptr_dst,
&rnaptr_src,
nullptr,
local->override_library,
static_cast<eRNAOverrideApplyFlag>(RNA_OVERRIDE_APPLY_FLAG_SKIP_RESYNC_CHECK |
RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY));
LISTBASE_FOREACH_MUTABLE (
IDOverrideLibraryProperty *, op, &local->override_library->properties) {
if (op->tag & IDOVERRIDE_LIBRARY_PROPERTY_TAG_NEEDS_RETORE) {
BKE_lib_override_library_property_delete(local->override_library, op);
}
}
local->override_library->runtime->tag &= ~IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RESTORE;
if (r_report_flags != nullptr) {
*r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
}
}
struct LibOverrideOpCreateData {
Main *bmain;
@ -3368,8 +3416,12 @@ static void lib_override_library_operations_create_cb(TaskPool *__restrict pool,
ID *id = static_cast<ID *>(taskdata);
eRNAOverrideMatchResult report_flags = RNA_OVERRIDE_MATCH_RESULT_INIT;
BKE_lib_override_library_operations_create(
create_data->bmain, id, reinterpret_cast<int *>(&report_flags));
lib_override_library_operations_create(
create_data->bmain,
id,
static_cast<eRNAOverrideMatch>(RNA_OVERRIDE_COMPARE_CREATE |
RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE),
&report_flags);
atomic_fetch_and_or_uint32(reinterpret_cast<uint32_t *>(&create_data->report_flags),
report_flags);
}
@ -3443,6 +3495,13 @@ void BKE_lib_override_library_main_operations_create(Main *bmain,
BLI_task_pool_free(task_pool);
if (create_pool_data.report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED) {
BKE_lib_override_library_main_operations_restore(
bmain, reinterpret_cast<int *>(&create_pool_data.report_flags));
create_pool_data.report_flags = static_cast<eRNAOverrideMatchResult>(
(create_pool_data.report_flags & ~RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED));
}
if (r_report_flags != nullptr) {
*r_report_flags |= create_pool_data.report_flags;
}
@ -3456,6 +3515,28 @@ void BKE_lib_override_library_main_operations_create(Main *bmain,
#endif
}
void BKE_lib_override_library_main_operations_restore(Main *bmain, int *r_report_flags)
{
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!(!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
(id->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RESTORE) !=
0)) {
continue;
}
/* Only restore overrides if we do have the real reference data available, and not some empty
* 'placeholder' for missing data (broken links). */
if (id->override_library->reference->tag & LIB_TAG_MISSING) {
continue;
}
BKE_lib_override_library_operations_restore(bmain, id, r_report_flags);
}
FOREACH_MAIN_ID_END;
}
static bool lib_override_library_id_reset_do(Main *bmain,
ID *id_root,
const bool do_reset_system_override)

View File

@ -274,6 +274,9 @@ typedef struct IDOverrideLibraryProperty {
enum {
/** This override property (operation) is unused and should be removed by cleanup process. */
IDOVERRIDE_LIBRARY_TAG_UNUSED = 1 << 0,
/** This override property is forbidden and should be restored to its linked reference value. */
IDOVERRIDE_LIBRARY_PROPERTY_TAG_NEEDS_RETORE = 1 << 1,
};
#
@ -287,6 +290,12 @@ typedef struct IDOverrideLibraryRuntime {
enum {
/** This override needs to be reloaded. */
IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD = 1 << 0,
/**
* This override contains properties with forbidden changes, which should be restored to their
* linked reference value.
*/
IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RESTORE = 1 << 1,
};
/* Main container for all overriding data info of a data-block. */

View File

@ -798,8 +798,10 @@ typedef enum eRNAOverrideMatch {
/** Create new property override if needed and possible. */
RNA_OVERRIDE_COMPARE_CREATE = 1 << 16,
/** Restore property's value(s) to reference ones if needed and possible. */
/** Restore property's value(s) to reference ones, if needed and possible. */
RNA_OVERRIDE_COMPARE_RESTORE = 1 << 17,
/** Tag for restoration of property's value(s) to reference ones, if needed and possible. */
RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE = 1 << 18,
} eRNAOverrideMatch;
typedef enum eRNAOverrideMatchResult {
@ -810,8 +812,13 @@ typedef enum eRNAOverrideMatchResult {
* differences between local and reference.
*/
RNA_OVERRIDE_MATCH_RESULT_CREATED = 1 << 0,
/**
* Some properties are illegaly different from their reference values and have been tagged for
* restoration.
*/
RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED = 1 << 1,
/** Some properties were reset to reference values. */
RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1,
RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 2,
} eRNAOverrideMatchResult;
typedef enum eRNAOverrideStatus {
@ -861,6 +868,12 @@ typedef enum eRNAOverrideApplyFlag {
* pointers properties, unless the destination original value (the one being overridden) is NULL.
*/
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0,
/** Do not check for liboverrides needing resync with their linked reference data. */
RNA_OVERRIDE_APPLY_FLAG_SKIP_RESYNC_CHECK = 1 << 1,
/** Only perform restore operations. */
RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY = 1 << 2,
} eRNAOverrideApplyFlag;
/**

View File

@ -633,6 +633,7 @@ bool RNA_struct_override_matches(Main *bmain,
const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
const bool do_tag_for_restore = (flags & RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE) != 0;
#ifdef DEBUG_OVERRIDE_TIMEIT
static float _sum_time_global = 0.0f;
@ -779,7 +780,7 @@ bool RNA_struct_override_matches(Main *bmain,
}
#endif
eRNAOverrideMatchResult report_flags = 0;
eRNAOverrideMatchResult report_flags = RNA_OVERRIDE_MATCH_RESULT_INIT;
const int diff = rna_property_override_diff(bmain,
&prop_local,
&prop_reference,
@ -800,7 +801,7 @@ bool RNA_struct_override_matches(Main *bmain,
matching = matching && diff == 0;
if (r_report_flags) {
*r_report_flags |= report_flags;
*r_report_flags = (*r_report_flags | report_flags);
}
if (diff != 0) {
@ -812,29 +813,52 @@ bool RNA_struct_override_matches(Main *bmain,
BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false);
}
if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
if ((do_restore || do_tag_for_restore) &&
(report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
/* We are allowed to restore to reference's values. */
if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
/* We should restore that property to its reference value */
if (RNA_property_editable(ptr_local, rawprop)) {
IDOverrideLibraryPropertyOperation opop_tmp = {
.operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
.subitem_reference_index = -1,
.subitem_local_index = -1,
};
rna_property_override_operation_apply(bmain,
ptr_local,
ptr_reference,
NULL,
rawprop,
rawprop,
NULL,
NULL,
NULL,
NULL,
&opop_tmp);
if (r_report_flags) {
*r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
/* This property should be restored to its reference value. This should not be done
* here, since this code may be called from non-main thread (modifying data through RNA
* is not thread safe). */
BLI_assert(op == NULL); /* Forbidden orverride prop should not exist currently. */
if (do_restore) {
IDOverrideLibraryPropertyOperation opop_tmp = {
.operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
.subitem_reference_index = -1,
.subitem_local_index = -1,
};
rna_property_override_operation_apply(bmain,
ptr_local,
ptr_reference,
NULL,
rawprop,
rawprop,
NULL,
NULL,
NULL,
NULL,
&opop_tmp);
if (r_report_flags) {
*r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
}
}
else {
if (op == NULL) {
/* An override property is needed, create a temp one if necessary. */
op = BKE_lib_override_library_property_get(override, rna_path, NULL);
BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, true);
}
BKE_lib_override_library_property_operation_get(
op, IDOVERRIDE_LIBRARY_OP_REPLACE, NULL, NULL, -1, -1, false, NULL, NULL);
BKE_lib_override_library_operations_tag(
op, IDOVERRIDE_LIBRARY_PROPERTY_TAG_NEEDS_RETORE, true);
override->runtime->tag |= IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RESTORE;
if (r_report_flags) {
*r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED;
}
}
}
else {
@ -850,7 +874,7 @@ bool RNA_struct_override_matches(Main *bmain,
else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) {
/* This property is not overridden, and differs from reference, so we have no match. */
matching = false;
if (!(do_create || do_restore)) {
if (!(do_create || do_restore || do_tag_for_restore)) {
/* Since we have no 'changing' action allowed, we can break here. */
if (rna_path != rna_path_buffer) {
MEM_freeN(rna_path);
@ -1188,132 +1212,30 @@ void RNA_struct_override_apply(Main *bmain,
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_START_AVERAGED(RNA_struct_override_apply);
#endif
const bool do_restore_only = (flag & RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY) != 0;
/* NOTE: Applying insert operations in a separate pass is mandatory.
* We could optimize this later, but for now, as inefficient as it is,
* don't think this is a critical point.
*/
bool do_insert = false;
for (int i = 0; i < 2; i++, do_insert = true) {
for (int i = 0; i < (do_restore_only ? 1 : 2); i++, do_insert = true) {
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
if (do_restore_only && (op->tag % IDOVERRIDE_LIBRARY_PROPERTY_TAG_NEEDS_RETORE) == 0) {
continue;
}
/* That tag should only exist for short lifespan when restoring values from reference linked
* data. */
BLI_assert((op->tag & IDOVERRIDE_LIBRARY_PROPERTY_TAG_NEEDS_RETORE) == 0 || do_restore_only);
/* Simplified for now! */
PointerRNA data_src, data_dst;
PointerRNA data_item_src, data_item_dst;
PropertyRNA *prop_src, *prop_dst;
if (RNA_path_resolve_property_and_item_pointer(
ptr_dst, op->rna_path, &data_dst, &prop_dst, &data_item_dst) &&
RNA_path_resolve_property_and_item_pointer(
ptr_src, op->rna_path, &data_src, &prop_src, &data_item_src)) {
PointerRNA data_storage, data_item_storage;
PropertyRNA *prop_storage = NULL;
/* It is totally OK if this does not success,
* only a subset of override operations actually need storage. */
if (ptr_storage && (ptr_storage->owner_id != NULL)) {
RNA_path_resolve_property_and_item_pointer(
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) {
if (op->rna_prop_type == PROP_POINTER &&
(((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag &
IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
BLI_assert(RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src)));
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);
rna_property_override_check_resync(
bmain, ptr_dst, ptr_src, &prop_ptr_dst, &prop_ptr_src);
}
else if (op->rna_prop_type == PROP_COLLECTION) {
if (RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src))) {
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));
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
continue;
}
PointerRNA *ptr_item_dst, *ptr_item_src;
PointerRNA private_ptr_item_dst, private_ptr_item_src;
rna_porperty_override_collection_subitem_lookup(ptr_dst,
ptr_src,
NULL,
prop_dst,
prop_src,
NULL,
&ptr_item_dst,
&ptr_item_src,
NULL,
&private_ptr_item_dst,
&private_ptr_item_src,
NULL,
op,
opop);
rna_property_override_check_resync(
bmain, ptr_dst, ptr_src, ptr_item_dst, ptr_item_src);
}
}
}
}
/* Workaround for older broken overrides, we then assume that non-matching ID pointers
* override operations that replace a non-NULL value are 'mistakes', and ignore (do not
* apply) them. */
if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) != 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_dst = RNA_property_pointer_get(&data_dst, prop_dst);
if (prop_ptr_dst.type != NULL && RNA_struct_is_ID(prop_ptr_dst.type)) {
#ifndef NDEBUG
PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
BLI_assert(prop_ptr_src.type == NULL || RNA_struct_is_ID(prop_ptr_src.type));
#endif
ID *id_dst = rna_property_override_property_real_id_owner(
bmain, &prop_ptr_dst, NULL, NULL);
if (id_dst != NULL) {
CLOG_INFO(&LOG,
4,
"%s: Ignoring local override on ID pointer property '%s', as requested by "
"RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
ptr_dst->owner_id->name,
op->rna_path);
continue;
}
}
}
rna_property_override_apply_ex(bmain,
&data_dst,
&data_src,
prop_storage ? &data_storage : NULL,
prop_dst,
prop_src,
prop_storage,
&data_item_dst,
&data_item_src,
prop_storage ? &data_item_storage : NULL,
op,
do_insert);
}
else {
if (!(RNA_path_resolve_property_and_item_pointer(
ptr_dst, op->rna_path, &data_dst, &prop_dst, &data_item_dst) &&
RNA_path_resolve_property_and_item_pointer(
ptr_src, op->rna_path, &data_src, &prop_src, &data_item_src))) {
CLOG_INFO(&LOG,
4,
"Failed to apply library override operation to '%s.%s' "
@ -1322,7 +1244,117 @@ void RNA_struct_override_apply(Main *bmain,
op->rna_path,
RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
continue;
}
PointerRNA data_storage, data_item_storage;
PropertyRNA *prop_storage = NULL;
/* It is totally OK if this does not success,
* only a subset of override operations actually need storage. */
if (ptr_storage && (ptr_storage->owner_id != NULL)) {
RNA_path_resolve_property_and_item_pointer(
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 ((flag & RNA_OVERRIDE_APPLY_FLAG_SKIP_RESYNC_CHECK) == 0 &&
(ptr_dst->owner_id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0) {
if (op->rna_prop_type == PROP_POINTER &&
(((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag &
IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
BLI_assert(RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src)));
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);
rna_property_override_check_resync(
bmain, ptr_dst, ptr_src, &prop_ptr_dst, &prop_ptr_src);
}
else if (op->rna_prop_type == PROP_COLLECTION) {
if (RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src))) {
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));
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
continue;
}
PointerRNA *ptr_item_dst, *ptr_item_src;
PointerRNA private_ptr_item_dst, private_ptr_item_src;
rna_porperty_override_collection_subitem_lookup(ptr_dst,
ptr_src,
NULL,
prop_dst,
prop_src,
NULL,
&ptr_item_dst,
&ptr_item_src,
NULL,
&private_ptr_item_dst,
&private_ptr_item_src,
NULL,
op,
opop);
rna_property_override_check_resync(
bmain, ptr_dst, ptr_src, ptr_item_dst, ptr_item_src);
}
}
}
}
/* Workaround for older broken overrides, we then assume that non-matching ID pointers
* override operations that replace a non-NULL value are 'mistakes', and ignore (do not
* apply) them. */
if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) != 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_dst = RNA_property_pointer_get(&data_dst, prop_dst);
if (prop_ptr_dst.type != NULL && RNA_struct_is_ID(prop_ptr_dst.type)) {
#ifndef NDEBUG
PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
BLI_assert(prop_ptr_src.type == NULL || RNA_struct_is_ID(prop_ptr_src.type));
#endif
ID *id_dst = rna_property_override_property_real_id_owner(
bmain, &prop_ptr_dst, NULL, NULL);
if (id_dst != NULL) {
CLOG_INFO(&LOG,
4,
"%s: Ignoring local override on ID pointer property '%s', as requested by "
"RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
ptr_dst->owner_id->name,
op->rna_path);
continue;
}
}
}
rna_property_override_apply_ex(bmain,
&data_dst,
&data_src,
prop_storage ? &data_storage : NULL,
prop_dst,
prop_src,
prop_storage,
&data_item_dst,
&data_item_src,
prop_storage ? &data_item_storage : NULL,
op,
do_insert);
}
}