diff --git a/source/blender/animrig/intern/versioning.cc b/source/blender/animrig/intern/versioning.cc index 92d8a93085e..c28a83f1c68 100644 --- a/source/blender/animrig/intern/versioning.cc +++ b/source/blender/animrig/intern/versioning.cc @@ -18,6 +18,7 @@ #include "DNA_action_defaults.h" #include "DNA_action_types.h" +#include "BKE_lib_id.hh" #include "BKE_main.hh" #include "BKE_node.hh" #include "BKE_report.hh" @@ -138,7 +139,7 @@ void convert_legacy_animato_action(bAction &dna_action) void tag_action_user_for_slotted_actions_conversion(ID &animated_id) { - animated_id.runtime.readfile_data->tags.action_assignment_needs_slot = true; + animated_id.runtime->readfile_data->tags.action_assignment_needs_slot = true; } void tag_action_users_for_slotted_actions_conversion(Main &bmain) diff --git a/source/blender/blenkernel/BKE_lib_id.hh b/source/blender/blenkernel/BKE_lib_id.hh index a1242cd5554..2b2079f8ea6 100644 --- a/source/blender/blenkernel/BKE_lib_id.hh +++ b/source/blender/blenkernel/BKE_lib_id.hh @@ -42,8 +42,10 @@ #include "DNA_userdef_enums.h" struct BlendWriter; +struct Depsgraph; struct GHash; struct ID; +struct ID_Readfile_Data; struct Library; struct ListBase; struct Main; @@ -51,6 +53,41 @@ struct PointerRNA; struct PropertyRNA; struct bContext; +namespace blender::bke::id { + +/** Status used and counters created during id-remapping. */ +struct ID_Runtime_Remap { + /** Status during ID remapping. */ + int status = 0; + /** During ID remapping the number of skipped use cases that refcount the data-block. */ + int skipped_refcounted = 0; + /** + * During ID remapping the number of direct use cases that could be remapped + * (e.g. obdata when in edit mode). + */ + int skipped_direct = 0; + /** During ID remapping, the number of indirect use cases that could not be remapped. */ + int skipped_indirect = 0; +}; + +struct ID_Runtime { + ID_Runtime_Remap remap = {}; + /** + * The depsgraph that owns this data block. This is only set on data-blocks which are + * copied-on-eval by the depsgraph. Additional data-blocks created during depsgraph evaluation + * are not owned by any specific depsgraph and thus this pointer is null for those. + */ + Depsgraph *depsgraph = nullptr; + + /** + * This data is only allocated & used during the readfile process. After that, the memory is + * freed and the pointer set to `nullptr`. + */ + ID_Readfile_Data *readfile_data = nullptr; +}; + +} // namespace blender::bke::id + /** * Get allocation size of a given data-block type and optionally allocation `r_name`. */ @@ -58,6 +95,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **r_name); /** * Allocates and returns memory of the right size for the specified block type, * initialized to zero. + * + * \note: Typically, caller also needs to immediately call #BKE_libblock_runtime_ensure on the + * allocated ID data. */ ID *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT; /** @@ -90,6 +130,14 @@ void *BKE_libblock_alloc_in_lib(Main *bmain, */ void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1); +/** + * Ensure that the given ID does have a valid runtime data. + * + * Low-level API, should not be needed in typical ID usages, where ID::runtime can always be + * assumed valid. + */ +void BKE_libblock_runtime_ensure(ID &id); + /** * Reset the runtime counters used by ID remapping. */ @@ -445,20 +493,35 @@ enum { /** * Low-level ID freeing functions. * - * \note These functions do NOT cover embedded IDs. Those are managed by the + * \note These `BKE_libblock_free_` functions do NOT cover embedded IDs. Those are managed by the * owning ID, and are typically allocated/freed from the IDType callbacks. */ -void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL(); -void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL(); -void BKE_libblock_free_runtime_data(ID *id) ATTR_NONNULL(); /** + * Only free generic Python instance data (ID::py_instance). + * * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly * this function will need to be called too, if Python has access to the data. * * ID data-blocks such as #Material.nodetree are not stored in #Main. */ void BKE_libblock_free_data_py(ID *id); +/** + * Only free generic runtime data (ID::runtime). + * + * In most cases #BKE_libblock_free_data handles this, but in rare cases (currently in readfile, + * when freeing linked ID placeholders), it is necessary. + */ +void BKE_libblock_free_runtime_data(ID *id); + +/** Free generic ID data, including the runtime and animation data, but not the python data. */ +void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL(); + +/** + * Free IDtype-specific data (does _not_ free generic ID data, use + * #BKE_libblock_free_data for that). + */ +void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL(); /** * Complete ID freeing, extended version for corner cases. diff --git a/source/blender/blenkernel/intern/lib_id.cc b/source/blender/blenkernel/intern/lib_id.cc index 82f1a2afa96..fc3bc9c10b2 100644 --- a/source/blender/blenkernel/intern/lib_id.cc +++ b/source/blender/blenkernel/intern/lib_id.cc @@ -1300,6 +1300,13 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) * * **************************** */ +void BKE_libblock_runtime_ensure(ID &id) +{ + if (!id.runtime) { + id.runtime = MEM_new(__func__); + } +} + size_t BKE_libblock_get_alloc_info(short type, const char **r_name) { const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type); @@ -1322,7 +1329,8 @@ ID *BKE_libblock_alloc_notest(short type) const char *name; size_t size = BKE_libblock_get_alloc_info(type, &name); if (size != 0) { - return static_cast(MEM_callocN(size, name)); + ID *id = static_cast(MEM_callocN(size, name)); + return id; } BLI_assert_msg(0, "Request to allocate unknown data type"); return nullptr; @@ -1339,6 +1347,7 @@ void *BKE_libblock_alloc_in_lib(Main *bmain, BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_LOCAL) == 0); ID *id = BKE_libblock_alloc_notest(type); + BKE_libblock_runtime_ensure(*id); if (id) { if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) { @@ -1443,10 +1452,10 @@ void BKE_libblock_init_empty(ID *id) void BKE_libblock_runtime_reset_remapping_status(ID *id) { - id->runtime.remap.status = 0; - id->runtime.remap.skipped_refcounted = 0; - id->runtime.remap.skipped_direct = 0; - id->runtime.remap.skipped_indirect = 0; + id->runtime->remap.status = 0; + id->runtime->remap.skipped_refcounted = 0; + id->runtime->remap.skipped_direct = 0; + id->runtime->remap.skipped_indirect = 0; } /* ********** ID session-wise UID management. ********** */ @@ -1550,6 +1559,7 @@ void BKE_libblock_copy_in_lib(Main *bmain, * Clear and initialize it similar to BKE_libblock_alloc_in_lib. */ const size_t size = BKE_libblock_get_alloc_info(GS(id->name), nullptr); memset(new_id, 0, size); + BKE_libblock_runtime_ensure(*new_id); STRNCPY(new_id->name, id->name); new_id->us = 0; new_id->tag |= ID_TAG_NOT_ALLOCATED | ID_TAG_NO_MAIN | ID_TAG_NO_USER_REFCOUNT; diff --git a/source/blender/blenkernel/intern/lib_id_delete.cc b/source/blender/blenkernel/intern/lib_id_delete.cc index e3775dc1bc3..72e3828ba48 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.cc +++ b/source/blender/blenkernel/intern/lib_id_delete.cc @@ -71,9 +71,9 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) MEM_freeN(id->library_weak_reference); } - BKE_libblock_free_runtime_data(id); - BKE_animdata_free(id, do_id_user); + + BKE_libblock_free_runtime_data(id); } void BKE_libblock_free_datablock(ID *id, const int /*flag*/) @@ -92,11 +92,15 @@ void BKE_libblock_free_datablock(ID *id, const int /*flag*/) void BKE_libblock_free_runtime_data(ID *id) { - /* During "normal" file loading this data is released when versioning ends. Some versioning code - * also deletes IDs, though. For example, in the startup blend file, brushes that were replaced - * by assets are deleted. This means that the regular "delete this ID" flow (aka this code here) - * also needs to free this data. */ - BLO_readfile_id_runtime_data_free(*id); + if (id->runtime) { + /* During "normal" file loading this data is released when versioning ends. Some versioning + * code also deletes IDs, though. For example, in the startup blend file, brushes that were + * replaced by assets are deleted. This means that the regular "delete this ID" flow (aka this + * code here) also needs to free this data. */ + BLO_readfile_id_runtime_data_free(*id); + + MEM_SAFE_DELETE(id->runtime); + } } static int id_free(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag) diff --git a/source/blender/blenkernel/intern/lib_remap.cc b/source/blender/blenkernel/intern/lib_remap.cc index 873536f0b98..d0f9f43736a 100644 --- a/source/blender/blenkernel/intern/lib_remap.cc +++ b/source/blender/blenkernel/intern/lib_remap.cc @@ -82,21 +82,21 @@ static void foreach_libblock_remap_callback_skip(const ID * /*id_owner*/, BLI_assert(id != nullptr); if (is_indirect) { - id->runtime.remap.skipped_indirect++; + id->runtime->remap.skipped_indirect++; } else if (violates_never_null || is_obj_editmode || is_reference) { - id->runtime.remap.skipped_direct++; + id->runtime->remap.skipped_direct++; } else { BLI_assert_unreachable(); } if (cb_flag & IDWALK_CB_USER) { - id->runtime.remap.skipped_refcounted++; + id->runtime->remap.skipped_refcounted++; } else if (cb_flag & IDWALK_CB_USER_ONE) { /* No need to count number of times this happens, just a flag is enough. */ - id->runtime.remap.status |= ID_REMAP_IS_USER_ONE_SKIPPED; + id->runtime->remap.status |= ID_REMAP_IS_USER_ONE_SKIPPED; } } @@ -141,7 +141,7 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner, ID *new_id = violates_never_null ? nullptr : *id_ptr; if (!is_indirect && new_id) { - new_id->runtime.remap.status |= ID_REMAP_IS_LINKED_DIRECT; + new_id->runtime->remap.status |= ID_REMAP_IS_LINKED_DIRECT; } if (skip_user_refcount) { @@ -444,7 +444,7 @@ static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, IDRemap *id_ } if (new_id != nullptr && (new_id->tag & ID_TAG_INDIRECT) && - (new_id->runtime.remap.status & ID_REMAP_IS_LINKED_DIRECT)) + (new_id->runtime->remap.status & ID_REMAP_IS_LINKED_DIRECT)) { new_id->tag &= ~ID_TAG_INDIRECT; new_id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK; @@ -569,13 +569,13 @@ static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, i * count has actually been incremented for that, we have to decrease once more its user * count... unless we had to skip some 'user_one' cases. */ if ((old_id->tag & ID_TAG_EXTRAUSER_SET) && - !(old_id->runtime.remap.status & ID_REMAP_IS_USER_ONE_SKIPPED)) + !(old_id->runtime->remap.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { id_us_clear_real(old_id); } } - const int skipped_refcounted = old_id->runtime.remap.skipped_refcounted; + const int skipped_refcounted = old_id->runtime->remap.skipped_refcounted; if (old_id->us - skipped_refcounted < 0) { CLOG_ERROR(&LOG, "Error in remapping process from '%s' (%p) to '%s' (%p): " @@ -587,7 +587,7 @@ static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, i old_id->us - skipped_refcounted); } - const int skipped_direct = old_id->runtime.remap.skipped_direct; + const int skipped_direct = old_id->runtime->remap.skipped_direct; if (skipped_direct == 0) { /* old_id is assumed to not be used directly anymore... */ if (old_id->lib && (old_id->tag & ID_TAG_EXTERN)) { diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 375b03fe105..e130c354ac6 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -2191,29 +2191,29 @@ static int direct_link_id_restore_recalc(const FileData *fd, static void readfile_id_runtime_data_ensure(ID &id) { - if (id.runtime.readfile_data) { + if (id.runtime->readfile_data) { return; } - id.runtime.readfile_data = MEM_callocN(__func__); + id.runtime->readfile_data = MEM_callocN(__func__); } ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id) { - if (!id.runtime.readfile_data) { + if (!id.runtime->readfile_data) { return ID_Readfile_Data::Tags{}; } - return id.runtime.readfile_data->tags; + return id.runtime->readfile_data->tags; } ID_Readfile_Data::Tags &BLO_readfile_id_runtime_tags_for_write(ID &id) { readfile_id_runtime_data_ensure(id); - return id.runtime.readfile_data->tags; + return id.runtime->readfile_data->tags; } void BLO_readfile_id_runtime_data_free(ID &id) { - MEM_SAFE_FREE(id.runtime.readfile_data); + MEM_SAFE_FREE(id.runtime->readfile_data); } void BLO_readfile_id_runtime_data_free_all(Main &bmain) @@ -2246,6 +2246,9 @@ static void direct_link_id_common(BlendDataReader *reader, const int id_tag, const ID_Readfile_Data::Tags id_read_tags) { + BLI_assert(id->runtime == nullptr); + BKE_libblock_runtime_ensure(*id); + if (!BLO_read_data_is_undo(reader)) { /* When actually reading a file, we do want to reset/re-generate session UIDS. * In undo case, we want to re-use existing ones. */ @@ -2271,13 +2274,8 @@ static void direct_link_id_common(BlendDataReader *reader, id->tag = id_tag; } - if (!BLO_read_data_is_undo(reader)) { - /* Reset the runtime data, as there were versions of Blender that did not do - * this before writing to disk. */ - id->runtime = ID_Runtime{}; - } readfile_id_runtime_data_ensure(*id); - id->runtime.readfile_data->tags = id_read_tags; + id->runtime->readfile_data->tags = id_read_tags; if ((id_tag & ID_TAG_TEMP_MAIN) == 0) { BKE_lib_libblock_session_uid_ensure(id); @@ -2561,6 +2559,7 @@ static ID *create_placeholder(Main *mainvar, { ListBase *lb = which_libbase(mainvar, idcode); ID *ph_id = BKE_libblock_alloc_notest(idcode); + BKE_libblock_runtime_ensure(*ph_id); *((short *)ph_id->name) = idcode; BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2); @@ -4953,15 +4952,19 @@ static void read_library_linked_ids(FileData *basefd, FileData *fd, Main *mainva /* Transfer the readfile data from the placeholder to the real ID, but * only if the real ID has no readfile data yet. The same realid may be * referred to by multiple placeholders. */ - if (realid && !realid->runtime.readfile_data) { - realid->runtime.readfile_data = id->runtime.readfile_data; - id->runtime.readfile_data = nullptr; + if (realid && !realid->runtime->readfile_data) { + realid->runtime->readfile_data = id->runtime->readfile_data; + id->runtime->readfile_data = nullptr; } - /* The 'readfile' runtime data needs to be freed here, as this ID placeholder does not go - * through versioning (the usual place where this data is freed). Since `id` is not a real - * ID, this shouldn't follow any pointers to embedded IDs. */ - BLO_readfile_id_runtime_data_free(*id); + /* Ensure that the runtime pointer, and its 'readfile' sub-data, are properly freed, as + * this ID placeholder does not go through versioning (the usual place where this data is + * freed). Since `id` is not a real ID, this shouldn't follow any pointers to embedded IDs. + * + * WARNING! This placeholder ID is only an ID struct, with a very small subset of regular + * ID common data actually valid and needing to be freed. Therefore, calling + * #BKE_libblock_free_data on it would not work. */ + BKE_libblock_free_runtime_data(id); MEM_freeN(id); } diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index a035ce11025..e7c7c8281e2 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1336,6 +1336,7 @@ BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, const bool is_undo, const bool is } temp_id->us = 0; temp_id->icon_id = 0; + temp_id->runtime = nullptr; /* Those listbase data change every time we add/remove an ID, and also often when * renaming one (due to re-sorting). This avoids generating a lot of false 'is changed' * detections between undo steps. */ @@ -1349,8 +1350,6 @@ BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, const bool is_undo, const bool is * when we need to re-read the ID into its original address, this is currently cleared in * #direct_link_id_common in `readfile.cc` anyway. */ temp_id->py_instance = nullptr; - /* Clear runtime data struct. */ - temp_id->runtime = ID_Runtime{}; } BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, BlendWriter *writer) diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 68eb54db081..93add3829a4 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -14,6 +14,7 @@ #include "BKE_action.hh" /* XXX: BKE_pose_channel_find_name */ #include "BKE_idtype.hh" +#include "BKE_lib_id.hh" #include "BKE_main.hh" #include "DNA_object_types.h" @@ -283,7 +284,7 @@ const ID *DEG_get_original_id(const ID *id) Depsgraph *DEG_get_depsgraph_by_id(const ID &id) { - return id.runtime.depsgraph; + return id.runtime->depsgraph; } bool DEG_is_original_id(const ID *id) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index de2530609cb..25b828d0e63 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -753,9 +753,15 @@ ID *deg_expand_eval_copy_datablock(const Depsgraph *depsgraph, const IDNode *id_ DEG_COW_PRINT( "Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); - /* Sanity checks. */ + /* Sanity checks. + * + * At this point, `id_cow` is essentially considered as a (partially dirty) allocated buffer (it + * has been freed, but not fully cleared, as a result of calling #deg_free_eval_copy_datablock on + * it). It is not expected to have any valid sub-data, not even a valid `ID::runtime` pointer. + */ BLI_assert(check_datablock_expanded(id_cow) == false); BLI_assert(id_cow->py_instance == nullptr); + BLI_assert(id_cow->runtime == nullptr); /* Copy data from original ID to a copied version. */ /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference @@ -1022,7 +1028,7 @@ void deg_tag_eval_copy_id(deg::Depsgraph &depsgraph, ID *id_cow, const ID *id_or /* This ID is no longer localized, is a self-sustaining copy now. */ id_cow->tag &= ~ID_TAG_LOCALIZED; id_cow->orig_id = (ID *)id_orig; - id_cow->runtime.depsgraph = &reinterpret_cast<::Depsgraph &>(depsgraph); + id_cow->runtime->depsgraph = &reinterpret_cast<::Depsgraph &>(depsgraph); } bool deg_eval_copy_is_expanded(const ID *id_cow) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 7da923ae296..f4cbc14059c 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -13,6 +13,7 @@ #include "DNA_ID.h" struct ID; +struct Depsgraph; /* Uncomment this to have verbose log about original and evaluated pointers * logged, with detailed information when they are allocated, expanded diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index ddcb7c883d7..aad8aad42f3 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -81,6 +81,8 @@ void IDNode::init_copy_on_write(ID *id_cow_hint) } else if (deg_eval_copy_is_needed(id_orig)) { id_cow = BKE_libblock_alloc_notest(GS(id_orig->name)); + /* No need to call #BKE_libblock_runtime_ensure here, this will be done by + * #BKE_libblock_copy_in_lib when #deg_expand_eval_copy_datablock is executed. */ DEG_COW_PRINT( "Allocate memory for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); } diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 446b9f66557..4d2363d0860 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -31,6 +31,7 @@ struct ARegion; struct AutoComplete; +struct Depsgraph; struct EnumPropertyItem; struct FileSelectParams; struct ID; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 092b12a0b3e..55e96221bfe 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -20,6 +20,9 @@ #ifdef __cplusplus # include +namespace blender::bke::id { +struct ID_Runtime; +} namespace blender::bke { struct PreviewImageRuntime; } @@ -29,6 +32,7 @@ struct IDPropertyGroupChildrenSet; namespace blender::bke::library { struct LibraryRuntime; } +using ID_RuntimeHandle = blender::bke::id::ID_Runtime; using PreviewImageRuntimeHandle = blender::bke::PreviewImageRuntime; using LibraryRuntimeHandle = blender::bke::library::LibraryRuntime; using IDPropertyGroupChildrenSet = blender::bke::idprop::IDPropertyGroupChildrenSet; @@ -36,6 +40,7 @@ using IDPropertyGroupChildrenSet = blender::bke::idprop::IDPropertyGroupChildren typedef struct PreviewImageRuntimeHandle PreviewImageRuntimeHandle; typedef struct LibraryRuntimeHandle LibraryRuntimeHandle; typedef struct IDPropertyGroupChildrenSet IDPropertyGroupChildrenSet; +typedef struct ID_RuntimeHandle ID_RuntimeHandle; #endif #ifdef __cplusplus @@ -45,11 +50,9 @@ extern "C" { struct FileData; struct GHash; struct ID; -struct ID_Readfile_Data; struct Library; struct PackedFile; struct UniqueName_Map; -struct Depsgraph; typedef struct IDPropertyUIData { /** Tool-tip / property description pointer. Owned by the #IDProperty. */ @@ -380,37 +383,6 @@ enum { ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, }; -/** Status used and counters created during id-remapping. */ -typedef struct ID_Runtime_Remap { - /** Status during ID remapping. */ - int status; - /** During ID remapping the number of skipped use cases that refcount the data-block. */ - int skipped_refcounted; - /** - * During ID remapping the number of direct use cases that could be remapped - * (e.g. obdata when in edit mode). - */ - int skipped_direct; - /** During ID remapping, the number of indirect use cases that could not be remapped. */ - int skipped_indirect; -} ID_Runtime_Remap; - -typedef struct ID_Runtime { - ID_Runtime_Remap remap; - /** - * The depsgraph that owns this data block. This is only set on data-blocks which are - * copied-on-eval by the depsgraph. Additional data-blocks created during depsgraph evaluation - * are not owned by any specific depsgraph and thus this pointer is null for those. - */ - struct Depsgraph *depsgraph; - - /** - * This data is only allocated & used during the readfile process. After that, the memory is - * freed and the pointer set to `nullptr`. - */ - struct ID_Readfile_Data *readfile_data; -} ID_Runtime; - typedef struct ID { /* There's a nasty circular dependency here.... 'void *' to the rescue! I * really wonder why this is needed. */ @@ -513,7 +485,17 @@ typedef struct ID { */ struct LibraryWeakReference *library_weak_reference; - struct ID_Runtime runtime; + /** + * Allocated runtime data, never written on disk or in undo steps. + * + * _Always_ valid for code handling IDs managed by the `BKE_lib_id` API. + * + * Internal low-level implementation of ID creation/copying/deletion, and code handling IDs + * themselves in non-standard ways (mainly the CoW IDs in depsgraph, and some temporary IDs in + * readfile) may have to manage this pointer themselves (see also #BKE_libblock_runtime_ensure + * and #BKE_libblock_free_runtime_data). + */ + ID_RuntimeHandle *runtime; } ID; /** diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 4949bfdc5fa..39b0127f287 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -43,8 +43,6 @@ typedef struct Mask { int flag; char _pad[4]; - void *_pad1; - Mask_Runtime runtime; } Mask; diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index b98594227cf..171d51c98a3 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -90,8 +90,6 @@ typedef struct MovieClip { /** Grease pencil data. */ struct bGPdata *gpd; - void *_pad1; - /** Data for SfM tracking. */ struct MovieTracking tracking; /** diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 189021e8455..2ded1c0a399 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2113,7 +2113,6 @@ typedef struct Scene { ListBase base DNA_DEPRECATED; /** Active base. */ struct Base *basact DNA_DEPRECATED; - void *_pad1; /** 3d cursor location. */ View3DCursor cursor; @@ -2138,7 +2137,6 @@ typedef struct Scene { /** Default allocated now. */ struct ToolSettings *toolsettings; - void *_pad4; struct DisplaySafeAreas safe_areas; /* Migrate or replace? depends on some internal things... */ @@ -2186,7 +2184,6 @@ typedef struct Scene { /** Physics simulation settings. */ struct PhysicsSettings physics_settings; - void *_pad8; /** * XXX: runtime flag for drawing, actually belongs in the window, * only used by #BKE_object_handle_update() diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index 091808f010b..9ef7af6416c 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -20,6 +20,8 @@ typedef struct bSound { ID id; + void *_pad1; + /** * The path to the sound file. */ diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 4f4a0ca15d8..a44deef7084 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -31,6 +31,8 @@ typedef struct Text { ID id; + void *_pad1; + /** * Optional file path, when NULL text is considered internal. * Otherwise this path will be used when saving/reloading. diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 143e1372a7c..69ed0e0874e 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -81,10 +81,11 @@ typedef struct Tex { /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; + void *_pad3; + float noisesize, turbul; float bright, contrast, saturation, rfac, gfac, bfac; float filtersize; - char _pad2[4]; /* newnoise: musgrave parameters */ float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain; @@ -122,7 +123,6 @@ typedef struct Tex { int sfra DNA_DEPRECATED; float checkerdist, nabla; - char _pad1[4]; struct ImageUser iuser; diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h index f47cd40eb36..815a777ce0a 100644 --- a/source/blender/makesdna/DNA_world_types.h +++ b/source/blender/makesdna/DNA_world_types.h @@ -49,17 +49,15 @@ typedef struct World { * bit 0: Do mist */ short mode; - char _pad2[6]; + + /** Assorted settings. */ + short flag; float misi, miststa, mistdist, misthi; /** Ambient occlusion. */ float aodist, aoenergy; - /** Assorted settings. */ - short flag; - char _pad3[2]; - /** Eevee settings. */ /** * Resolution of the world probe when baked to a texture. Contains `eLightProbeResolution`. @@ -73,11 +71,9 @@ typedef struct World { float sun_shadow_maximum_resolution; float sun_shadow_jitter_overblur; float sun_shadow_filter_radius; - char _pad4[4]; short pr_texture; short use_nodes DNA_DEPRECATED; - char _pad[4]; /* previews */ struct PreviewImage *preview; @@ -88,6 +84,8 @@ typedef struct World { /** Light-group membership information. */ struct LightgroupMembership *lightgroup; + void *_pad1; + /** Runtime. */ ListBase gpumaterial; /* The Depsgraph::update_count when this World was last updated. */