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:
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
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue