From f1c2a93623d5f50d6ba58fa4ff28857afcb51eb3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 1 Jul 2024 14:21:06 +0200 Subject: [PATCH] Refactor: Core: BKE_main: init/clear code. This commit allows to initialize and clear a Main struct which allocation is handled separately. There is no behavioral change expected from this commit. This is a requirement for incoming rewrite of the PartialWrite code (see #122061 and !122118). Pull Request: https://projects.blender.org/blender/blender/pulls/122118 --- source/blender/blenkernel/BKE_main.hh | 34 ++++++++- source/blender/blenkernel/intern/main.cc | 87 ++++++++++++++---------- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/source/blender/blenkernel/BKE_main.hh b/source/blender/blenkernel/BKE_main.hh index 040bb110f2c..112dc0b8ac7 100644 --- a/source/blender/blenkernel/BKE_main.hh +++ b/source/blender/blenkernel/BKE_main.hh @@ -271,8 +271,38 @@ struct Main { * \note Always generate a non-global Main, use #BKE_blender_globals_main_replace to put a newly * created one in `G_MAIN`. */ -Main *BKE_main_new(); -void BKE_main_free(Main *mainvar); +Main *BKE_main_new(void); +/** + * Initialize a Main data-base. + * + * \note Always generate a non-global Main, use #BKE_blender_globals_main_replace to put a newly + * created one in `G_MAIN`. + */ +void BKE_main_init(Main &bmain); +/** + * Make given \a bmain empty again, and free all runtime mappings. + * + * This is similar to a call to #BKE_main_destroy followed by #BKE_main_init, however the internal + * #Main::lock is kept unchanged, and the #Main::is_global_main flag is not reset to `true` either. + * + * \note: Unlike #BKE_main_free, only process the given \a bmain, without handling any potential + * other linked Main. + */ +void BKE_main_clear(Main &bmain); +/** + * Clear and free all data in given \a bmain, but does not free \a bmain itself. + * + * \note: In most cases, #BKE_main_free should be used instead of this function. + * + * \note: Unlike #BKE_main_free, only process the given \a bmain, without handling any potential + * other linked Main. + */ +void BKE_main_destroy(Main &bmain); +/** + * Completely destroy the given \a bmain, and all its linked 'libraries' ones if any (all other + * bmains, following the #Main.next chained list). + */ +void BKE_main_free(Main *bmain); /** Struct packaging log/report info about a Main merge result. */ struct MainMergeReport { diff --git a/source/blender/blenkernel/intern/main.cc b/source/blender/blenkernel/intern/main.cc index b9257f836ab..9f09b2967ab 100644 --- a/source/blender/blenkernel/intern/main.cc +++ b/source/blender/blenkernel/intern/main.cc @@ -45,43 +45,36 @@ static CLG_LogRef LOG = {"bke.main"}; Main *BKE_main_new() { Main *bmain = static_cast
(MEM_callocN(sizeof(Main), "new main")); - bmain->lock = static_cast(MEM_mallocN(sizeof(SpinLock), "main lock")); - BLI_spin_init((SpinLock *)bmain->lock); - bmain->is_global_main = false; + BKE_main_init(*bmain); + return bmain; +} + +void BKE_main_init(Main &bmain) +{ + bmain.lock = static_cast(MEM_mallocN(sizeof(SpinLock), "main lock")); + BLI_spin_init(reinterpret_cast(bmain.lock)); + bmain.is_global_main = false; /* Just rebuilding the Action Binding to ID* map once is likely cheaper than, * for every ID, when it's loaded from disk, check whether it's animated or * not, and then figure out which Main it went into, and then set the flag. */ - bmain->is_action_binding_to_id_map_dirty = true; - - return bmain; + bmain.is_action_binding_to_id_map_dirty = true; } -void BKE_main_free(Main *mainvar) +void BKE_main_clear(Main &bmain) { - /* In case this is called on a 'split-by-libraries' list of mains. - * - * Should not happen in typical usages, but can occur e.g. if a file reading is aborted. */ - if (mainvar->next) { - BKE_main_free(mainvar->next); - } - - /* Include this check here as the path may be manipulated after creation. */ - BLI_assert_msg(!(mainvar->filepath[0] == '/' && mainvar->filepath[1] == '/'), - "'.blend' relative \"//\" must not be used in Main!"); - - /* also call when reading a file, erase all, etc */ + /* Also call when reading a file, erase all, etc */ ListBase *lbarray[INDEX_ID_MAX]; int a; - /* Since we are removing whole main, no need to bother 'properly' - * (and slowly) removing each ID from it. */ + /* Since we are removing whole main, no need to bother 'properly' (and slowly) removing each ID + * from it. */ const int free_flag = (LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_DEG_TAG); - MEM_SAFE_FREE(mainvar->blen_thumb); + MEM_SAFE_FREE(bmain.blen_thumb); - a = set_listbasepointers(mainvar, lbarray); + a = set_listbasepointers(&bmain, lbarray); while (a--) { ListBase *lb = lbarray[a]; ID *id, *id_next; @@ -89,14 +82,14 @@ void BKE_main_free(Main *mainvar) for (id = static_cast(lb->first); id != nullptr; id = id_next) { id_next = static_cast(id->next); #if 1 - BKE_id_free_ex(mainvar, id, free_flag, false); + BKE_id_free_ex(&bmain, id, free_flag, false); #else /* Errors freeing ID's can be hard to track down, * enable this so VALGRIND or ASAN will give the line number in its error log. */ # define CASE_ID_INDEX(id_index) \ case id_index: \ - BKE_id_free_ex(mainvar, id, free_flag, false); \ + BKE_id_free_ex(&bmain, id, free_flag, false); \ break switch ((eID_Index)a) { @@ -153,25 +146,47 @@ void BKE_main_free(Main *mainvar) BLI_listbase_clear(lb); } - if (mainvar->relations) { - BKE_main_relations_free(mainvar); + if (bmain.relations) { + BKE_main_relations_free(&bmain); } - if (mainvar->id_map) { - BKE_main_idmap_destroy(mainvar->id_map); + if (bmain.id_map) { + BKE_main_idmap_destroy(bmain.id_map); } /* NOTE: `name_map` in libraries are freed together with the library IDs above. */ - if (mainvar->name_map) { - BKE_main_namemap_destroy(&mainvar->name_map); + if (bmain.name_map) { + BKE_main_namemap_destroy(&bmain.name_map); } - if (mainvar->name_map_global) { - BKE_main_namemap_destroy(&mainvar->name_map_global); + if (bmain.name_map_global) { + BKE_main_namemap_destroy(&bmain.name_map_global); + } +} + +void BKE_main_destroy(Main &bmain) +{ + BKE_main_clear(bmain); + + BLI_spin_end(reinterpret_cast(bmain.lock)); + MEM_freeN(bmain.lock); + bmain.lock = nullptr; +} + +void BKE_main_free(Main *bmain) +{ + /* In case this is called on a 'split-by-libraries' list of mains. + * + * Should not happen in typical usages, but can occur e.g. if a file reading is aborted. */ + if (bmain->next) { + BKE_main_free(bmain->next); } - BLI_spin_end((SpinLock *)mainvar->lock); - MEM_freeN(mainvar->lock); - MEM_freeN(mainvar); + /* Include this check here as the path may be manipulated after creation. */ + BLI_assert_msg(!(bmain->filepath[0] == '/' && bmain->filepath[1] == '/'), + "'.blend' relative \"//\" must not be used in Main!"); + + BKE_main_destroy(*bmain); + MEM_freeN(bmain); } static bool are_ids_from_different_mains_matching(Main *bmain_1, ID *id_1, Main *bmain_2, ID *id_2)