Liboverride: Refactor 'refresh' tagging and handling.

Move tagging from `flush_editors_id_update` to `deg::id_tag_update`.

Since ID relationships cannot always be trusted when tagging for update
happens (can happen e.g. during liboverride apply itself, when deleting
IDs, and so on), embedded IDs are simply tagged here too, instead of
directly tagging their owner ID.

Propagation from embedded to owner ID then happens when checking and
'consuming' the `LIB_TAG_LIBOVERRIDE_AUTOREFRESH` ID tag, in
`BKE_lib_override_library_main_operations_create`.

Pull Request: https://projects.blender.org/blender/blender/pulls/115319
This commit is contained in:
Bastien Montagne 2023-11-23 21:54:27 +01:00 committed by Gitea
parent d09d93febf
commit e14c9552c3
4 changed files with 53 additions and 27 deletions

View File

@ -104,6 +104,14 @@ bool BKE_lib_override_library_property_is_animated(
*/
bool BKE_lib_override_library_is_hierarchy_leaf(Main *bmain, ID *id);
/**
* Tag the liboverride ID for auto-refresh when it gets tagged for depsgraph update.
*
* NOTE: This should only handle direct user editing, it is assumed that indirct updates should
* never require an update of the liboverride diffing info.
*/
void BKE_lib_override_id_tag_on_deg_tag_from_user(ID *id);
/**
* Create an overridden local copy of linked reference.
*

View File

@ -422,6 +422,19 @@ bool BKE_lib_override_library_is_hierarchy_leaf(Main *bmain, ID *id)
return false;
}
void BKE_lib_override_id_tag_on_deg_tag_from_user(ID *id)
{
/* Only local liboverrides need to be tagged for refresh, linked ones should not be editable. */
if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY(id)) {
return;
}
/* NOTE: Valid relationships between IDs here (especially the beloved ObData <-> ShapeKey special
* case) cannot be always expected when ID get tagged. So now, embedded IDs and similar also get
* tagged, and the 'liboverride refresh' code is responsible to properly progagate the update to
* the owner ID when needed (see #BKE_lib_override_library_main_operations_create). */
id->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
}
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
@ -4368,9 +4381,33 @@ void BKE_lib_override_library_main_operations_create(Main *bmain,
TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH);
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
(force_auto || (id->tag & LIB_TAG_LIBOVERRIDE_AUTOREFRESH)))
{
if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
continue;
}
/* Propagate potential embedded data tagg to the owner ID (see also
* #BKE_lib_override_id_tag_on_deg_tag_from_user). */
if (Key *key = BKE_key_from_id(id)) {
if (key->id.tag & LIB_TAG_LIBOVERRIDE_AUTOREFRESH) {
key->id.tag &= ~LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
id->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
}
}
if (bNodeTree *ntree = ntreeFromID(id)) {
if (ntree->id.tag & LIB_TAG_LIBOVERRIDE_AUTOREFRESH) {
ntree->id.tag &= ~LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
id->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
}
}
if (GS(id->name) == ID_SCE) {
if (Collection *scene_collection = reinterpret_cast<Scene *>(id)->master_collection) {
if (scene_collection->id.tag & LIB_TAG_LIBOVERRIDE_AUTOREFRESH) {
scene_collection->id.tag &= ~LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
id->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
}
}
}
if (force_auto || (id->tag & LIB_TAG_LIBOVERRIDE_AUTOREFRESH)) {
/* Usual issue with pose, it's quiet rare but sometimes they may not be up to date when this
* function is called. */
if (GS(id->name) == ID_OB) {

View File

@ -31,6 +31,7 @@
#include "BKE_anim_data.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_override.hh"
#include "BKE_node.hh"
#include "BKE_scene.h"
#include "BKE_screen.hh"
@ -636,6 +637,10 @@ void id_tag_update(Main *bmain, ID *id, uint flags, eUpdateSource update_source)
graph_id_tag_update(bmain, depsgraph, id, flags, update_source);
}
if (update_source & DEG_UPDATE_SOURCE_USER_EDIT) {
BKE_lib_override_id_tag_on_deg_tag_from_user(id);
}
/* Accumulate all tags for an ID between two undo steps, so they can be
* replayed for undo. */
id->recalc_after_undo_push |= deg_recalc_flags_effective(nullptr, flags);

View File

@ -248,30 +248,6 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
if (deg_copy_on_write_is_expanded(id_cow)) {
if (graph->is_active && id_node->is_user_modified) {
deg_editors_id_update(update_ctx, id_orig);
/* We only want to tag an ID for lib-override auto-refresh if it was actually tagged as
* changed. CoW IDs indirectly modified because of changes in other IDs should never
* require a lib-override diffing. */
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_orig)) {
id_orig->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
}
else if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_orig)) {
switch (GS(id_orig->name)) {
case ID_KE:
((Key *)id_orig)->from->tag |= LIB_TAG_LIBOVERRIDE_AUTOREFRESH;
break;
case ID_GR:
BLI_assert(id_orig->flag & LIB_EMBEDDED_DATA);
/* TODO. */
break;
case ID_NT:
BLI_assert(id_orig->flag & LIB_EMBEDDED_DATA);
/* TODO. */
break;
default:
BLI_assert(0);
}
}
}
/* Inform draw engines that something was changed. */
flush_engine_data_update(id_cow);