IDType owner ID accessor: Add option to skip relationship sanity checks.

While currently, all cases where `BKE_id_owner_get` is called are
'safe', there are some points in code where the pointers ensureing the
relationship between an embedded ID and its owner are not (fully) valid.

This new option (`false` by default) allows to skip the debug asserts
ensuring the sanity of these 'owner <-> embedded' ID pointers in the
relevant `owner_pointer_get` callbacks.

This change is not expected to have any effect in current codebase.
This commit is contained in:
Bastien Montagne 2024-05-02 14:04:22 +02:00
parent 8ba6c16242
commit eb9bec54ad
6 changed files with 32 additions and 14 deletions

@ -89,7 +89,15 @@ using IDTypeForeachCacheFunction = void (*)(ID *id,
using IDTypeForeachPathFunction = void (*)(ID *id, BPathForeachPathData *bpath_data); using IDTypeForeachPathFunction = void (*)(ID *id, BPathForeachPathData *bpath_data);
using IDTypeEmbeddedOwnerPointerGetFunction = ID **(*)(ID *id); /**
* Callback returning the address of the pointer to the owner ID, for embedded (and Shapekey) ones.
*
* \param debug_relationship_assert: usually the owner <-> embedded relation pointers should be
* fully valid, and can be asserted on. But in some cases, they are not (fully) valid, e.g when
* copying an ID and all of its embedded data.
*/
using IDTypeEmbeddedOwnerPointerGetFunction = ID *
*(*)(ID * id, const bool debug_relationship_assert);
using IDTypeBlendWriteFunction = void (*)(BlendWriter *writer, ID *id, const void *id_address); using IDTypeBlendWriteFunction = void (*)(BlendWriter *writer, ID *id, const void *id_address);
using IDTypeBlendReadDataFunction = void (*)(BlendDataReader *reader, ID *id); using IDTypeBlendReadDataFunction = void (*)(BlendDataReader *reader, ID *id);

@ -711,8 +711,12 @@ bool BKE_id_can_be_asset(const ID *id);
* Return the owner ID of the given `id`, if any. * Return the owner ID of the given `id`, if any.
* *
* \note This will only return non-NULL for embedded IDs (master collections etc.), and shape-keys. * \note This will only return non-NULL for embedded IDs (master collections etc.), and shape-keys.
*
* \param debug_relationship_assert: True by default, whether to perform debug checks on validity
* of the pointers between owner and embedded IDs. In some cases, these relations are not yet
* (fully) valid, e.g. during ID copying.
*/ */
ID *BKE_id_owner_get(ID *id); ID *BKE_id_owner_get(ID *id, const bool debug_relationship_assert = true);
/** /**
* Check if that ID can be considered as editable from a high-level (editor) perspective. * Check if that ID can be considered as editable from a high-level (editor) perspective.

@ -249,7 +249,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
} }
} }
static ID **collection_owner_pointer_get(ID *id) static ID **collection_owner_pointer_get(ID *id, const bool debug_relationship_assert)
{ {
if ((id->flag & LIB_EMBEDDED_DATA) == 0) { if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
return nullptr; return nullptr;
@ -257,9 +257,11 @@ static ID **collection_owner_pointer_get(ID *id)
Collection *master_collection = (Collection *)id; Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0); BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
if (debug_relationship_assert) {
BLI_assert(master_collection->owner_id != nullptr); BLI_assert(master_collection->owner_id != nullptr);
BLI_assert(GS(master_collection->owner_id->name) == ID_SCE); BLI_assert(GS(master_collection->owner_id->name) == ID_SCE);
BLI_assert(((Scene *)master_collection->owner_id)->master_collection == master_collection); BLI_assert(((Scene *)master_collection->owner_id)->master_collection == master_collection);
}
return &master_collection->owner_id; return &master_collection->owner_id;
} }

@ -103,12 +103,14 @@ static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data)
} }
} }
static ID **shapekey_owner_pointer_get(ID *id) static ID **shapekey_owner_pointer_get(ID *id, const bool debug_relationship_assert)
{ {
Key *key = (Key *)id; Key *key = (Key *)id;
if (debug_relationship_assert) {
BLI_assert(key->from != nullptr); BLI_assert(key->from != nullptr);
BLI_assert(BKE_key_from_id(key->from) == key); BLI_assert(BKE_key_from_id(key->from) == key);
}
return &key->from; return &key->from;
} }

@ -2209,11 +2209,11 @@ bool BKE_id_can_be_asset(const ID *id)
BKE_idtype_idcode_is_linkable(GS(id->name)); BKE_idtype_idcode_is_linkable(GS(id->name));
} }
ID *BKE_id_owner_get(ID *id) ID *BKE_id_owner_get(ID *id, const bool debug_relationship_assert)
{ {
const IDTypeInfo *idtype = BKE_idtype_get_info_from_id(id); const IDTypeInfo *idtype = BKE_idtype_get_info_from_id(id);
if (idtype->owner_pointer_get != nullptr) { if (idtype->owner_pointer_get != nullptr) {
ID **owner_id_pointer = idtype->owner_pointer_get(id); ID **owner_id_pointer = idtype->owner_pointer_get(id, debug_relationship_assert);
if (owner_id_pointer != nullptr) { if (owner_id_pointer != nullptr) {
return *owner_id_pointer; return *owner_id_pointer;
} }

@ -456,7 +456,7 @@ static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
} }
} }
static ID **node_owner_pointer_get(ID *id) static ID **node_owner_pointer_get(ID *id, const bool debug_relationship_assert)
{ {
if ((id->flag & LIB_EMBEDDED_DATA) == 0) { if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
return nullptr; return nullptr;
@ -465,8 +465,10 @@ static ID **node_owner_pointer_get(ID *id)
// BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0); // BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0);
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id); bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
if (debug_relationship_assert) {
BLI_assert(ntree->owner_id != nullptr); BLI_assert(ntree->owner_id != nullptr);
BLI_assert(ntreeFromID(ntree->owner_id) == ntree); BLI_assert(ntreeFromID(ntree->owner_id) == ntree);
}
return &ntree->owner_id; return &ntree->owner_id;
} }