Core: support localizing data-block without owner ID

Previously, the owner-id on localized node trees, like the one created in
`GPU_material_from_nodetree` would have `bNodeTree::owner_id` set, even though
they were independent. The leads to asserts when using `BKE_id_owner_get` on the
localized node tree.

The `node_tree_localize` already took a `ID *new_owner_id` parameter. However,
if it was `nullptr` it was ignored instead actually clearing the `owner_id`.
This patch changes the parameter to `std::optional<ID *> new_owner_id`. Now,
`std::nullopt` means that the value is ignored and when `nullptr` is passed in,
the `owner_id` will be cleared on the localized tree.

Since `node_tree_localize` indirectly uses other functions, the same function
signature change is done in `BKE_libblock_copy_in_lib` and `BKE_id_copy_in_lib`.
The callers have been updated to pass in `nullopt` instead of `nullptr`.

Pull Request: https://projects.blender.org/blender/blender/pulls/133002
This commit is contained in:
Jacques Lucke
2025-01-13 16:46:36 +01:00
parent f7c6159229
commit 11f20683f9
8 changed files with 34 additions and 21 deletions

View File

@@ -231,12 +231,12 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int orig_fla
* not use any library (i.e. become a local ID). Use #std::nullopt for default behavior (i.e.
* behavior of the #BKE_libblock_copy_ex function).
* \param new_owner_id: When copying an embedded ID, the owner ID of the new copy. Should be
* `nullptr` for regular ID copying, or in case the owner ID is not (yet) known.
* `nullopt` for regular ID copying, or in case the owner ID is not (yet) known.
*/
void BKE_libblock_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
const ID *new_owner_id,
std::optional<const ID *> new_owner_id,
ID **new_id_p,
int orig_flag);
@@ -612,12 +612,12 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag);
* not use any library (i.e. become a local ID). Use #std::nullopt for default behavior (i.e.
* behavior of the #BKE_id_copy_ex function).
* \param new_owner_id: When copying an embedded ID, the owner ID of the new copy. Should be
* `nullptr` for regular ID copying, or in case the owner ID is not (yet) known.
* `nullopt` for regular ID copying, or in case the owner ID is not (yet) known.
*/
struct ID *BKE_id_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
const ID *new_owner_id,
std::optional<const ID *> new_owner_id,
ID **new_id_p,
int flag);
/**

View File

@@ -587,10 +587,10 @@ void node_tree_set_output(bNodeTree *ntree);
/**
* Returns localized tree for execution in threads.
*
* \param new_owner_id: the owner ID of the localized nodetree, may be null if unknown or
* \param new_owner_id: the owner ID of the localized nodetree, may be nullopt if unknown or
* irrelevant.
*/
bNodeTree *node_tree_localize(bNodeTree *ntree, ID *new_owner_id);
bNodeTree *node_tree_localize(bNodeTree *ntree, std::optional<ID *> new_owner_id);
/**
* This is only direct data, tree itself should have been written.

View File

@@ -381,14 +381,14 @@ AnimData *BKE_animdata_copy_in_lib(Main *bmain,
BKE_id_copy_in_lib(bmain,
owner_library,
reinterpret_cast<ID *>(dadt->action),
nullptr,
std::nullopt,
nullptr,
id_copy_flag));
dadt->tmpact = reinterpret_cast<bAction *>(
BKE_id_copy_in_lib(bmain,
owner_library,
reinterpret_cast<ID *>(dadt->tmpact),
nullptr,
std::nullopt,
nullptr,
id_copy_flag));
}

View File

@@ -11,6 +11,7 @@
#include <cstdlib>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@@ -1794,7 +1795,7 @@ ID *PartialWriteContext::id_add_copy(const ID *id, const bool regenerate_session
const int copy_flags = (LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
/* NOTE: Could make this an option if needed in the future */
LIB_ID_COPY_ASSET_METADATA);
ctx_root_id = BKE_id_copy_in_lib(nullptr, id->lib, id, nullptr, nullptr, copy_flags);
ctx_root_id = BKE_id_copy_in_lib(nullptr, id->lib, id, std::nullopt, nullptr, copy_flags);
ctx_root_id->tag |= ID_TAG_TEMP_MAIN;
if (regenerate_session_uid) {
/* Calling #BKE_lib_libblock_session_uid_renew is not needed here, copying already generated a

View File

@@ -2949,8 +2949,12 @@ static void legacy_gpencil_sanitize_annotations(Main &bmain)
/* Legacy GP data also used by objects. Create the duplicate of legacy GPv2 data for
* annotations, if not yet done. */
if (!new_annotation_gpd) {
new_annotation_gpd = reinterpret_cast<bGPdata *>(BKE_id_copy_in_lib(
&bmain, legacy_gpd->id.lib, &legacy_gpd->id, nullptr, nullptr, LIB_ID_COPY_DEFAULT));
new_annotation_gpd = reinterpret_cast<bGPdata *>(BKE_id_copy_in_lib(&bmain,
legacy_gpd->id.lib,
&legacy_gpd->id,
std::nullopt,
nullptr,
LIB_ID_COPY_DEFAULT));
new_annotation_gpd->flag |= GP_DATA_ANNOTATIONS;
id_us_min(&new_annotation_gpd->id);
annotations_gpv2.add_overwrite(legacy_gpd, new_annotation_gpd);

View File

@@ -14,6 +14,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@@ -656,7 +657,7 @@ bool BKE_id_copy_is_allowed(const ID *id)
ID *BKE_id_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
const ID *new_owner_id,
std::optional<const ID *> new_owner_id,
ID **new_id_p,
const int flag)
{
@@ -759,12 +760,12 @@ ID *BKE_id_copy_in_lib(Main *bmain,
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, const int flag)
{
return BKE_id_copy_in_lib(bmain, std::nullopt, id, nullptr, new_id_p, flag);
return BKE_id_copy_in_lib(bmain, std::nullopt, id, std::nullopt, new_id_p, flag);
}
ID *BKE_id_copy(Main *bmain, const ID *id)
{
return BKE_id_copy_in_lib(bmain, std::nullopt, id, nullptr, nullptr, LIB_ID_COPY_DEFAULT);
return BKE_id_copy_in_lib(bmain, std::nullopt, id, std::nullopt, nullptr, LIB_ID_COPY_DEFAULT);
}
ID *BKE_id_copy_for_duplicate(Main *bmain,
@@ -1510,7 +1511,7 @@ void *BKE_id_new_nomain(const short type, const char *name)
void BKE_libblock_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
const ID *new_owner_id,
std::optional<const ID *> new_owner_id,
ID **new_id_p,
const int orig_flag)
{
@@ -1585,11 +1586,17 @@ void BKE_libblock_copy_in_lib(Main *bmain,
* is given. In some cases (e.g. depsgraph), this is important for later remapping to work
* properly.
*/
if (new_owner_id) {
if (new_owner_id.has_value()) {
const IDTypeInfo *idtype = BKE_idtype_get_info_from_id(new_id);
BLI_assert(idtype->owner_pointer_get != nullptr);
ID **owner_id_pointer = idtype->owner_pointer_get(new_id, false);
*owner_id_pointer = const_cast<ID *>(new_owner_id);
if (owner_id_pointer) {
*owner_id_pointer = const_cast<ID *>(*new_owner_id);
if (*new_owner_id == nullptr) {
/* If the new id does not have an owner, it's also not embedded. */
new_id->flag &= ~ID_FLAG_EMBEDDED_DATA;
}
}
}
/* We do not want any handling of user-count in code duplicating the data here, we do that all
@@ -1647,14 +1654,14 @@ void BKE_libblock_copy_in_lib(Main *bmain,
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **new_id_p, const int orig_flag)
{
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, nullptr, new_id_p, orig_flag);
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, std::nullopt, new_id_p, orig_flag);
}
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn = nullptr;
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, nullptr, &idn, 0);
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, std::nullopt, &idn, 0);
return idn;
}

View File

@@ -10,6 +10,7 @@
#include <cstring>
#include <iostream>
#include <map>
#include <optional>
#include <queue>
#include "CLG_log.h"
@@ -266,7 +267,7 @@ static ID *lib_override_library_create_from(Main *bmain,
ID *local_id = BKE_id_copy_in_lib(bmain,
owner_library,
reference_id,
nullptr,
std::nullopt,
nullptr,
(LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG |

View File

@@ -3764,7 +3764,7 @@ void node_tree_node_flag_set(const bNodeTree *ntree, const int flag, const bool
}
}
bNodeTree *node_tree_localize(bNodeTree *ntree, ID *new_owner_id)
bNodeTree *node_tree_localize(bNodeTree *ntree, std::optional<ID *> new_owner_id)
{
if (ntree == nullptr) {
return nullptr;