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
This commit is contained in:
parent
8f8c825196
commit
f1c2a93623
@ -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 {
|
||||
|
@ -45,43 +45,36 @@ static CLG_LogRef LOG = {"bke.main"};
|
||||
Main *BKE_main_new()
|
||||
{
|
||||
Main *bmain = static_cast<Main *>(MEM_callocN(sizeof(Main), "new main"));
|
||||
bmain->lock = static_cast<MainLock *>(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<MainLock *>(MEM_mallocN(sizeof(SpinLock), "main lock"));
|
||||
BLI_spin_init(reinterpret_cast<SpinLock *>(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<ID *>(lb->first); id != nullptr; id = id_next) {
|
||||
id_next = static_cast<ID *>(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<SpinLock *>(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)
|
||||
|
Loading…
Reference in New Issue
Block a user