Fix T93058: Crash on opening old pre-2.80 .blend files.

Layer resync code would not yet fully properly deal with all possible
invalid status of ViewLayer comming from those older files.

Now put 2.80-doversion specific fixes into their own dedicated
function, so that they do not affect actual regular layer resync code
anymore. Also added some sanity-checks in main
`BKE_layer_collection_sync` code.
This commit is contained in:
Bastien Montagne 2022-01-25 16:42:31 +01:00
parent 6c25aabddf
commit 96667e3391
Notes: blender-bot 2023-02-14 00:13:36 +01:00
Referenced by issue #93058, Instant crash when opening some of the Eevee sample scenes
3 changed files with 41 additions and 12 deletions

View File

@ -157,6 +157,13 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La
void BKE_layer_collection_resync_forbid(void);
void BKE_layer_collection_resync_allow(void);
/** Helper to fix older pre-2.80 blendfiles.
*
* Ensures the given `view_layer` as a valid first-level layer collection, i.e. a single one
* matching the scene's master collection. This is a requirement for `BKE_layer_collection_sync`.
*/
void BKE_layer_collection_doversion_2_80(const struct Scene *scene, struct ViewLayer *view_layer);
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
/**

View File

@ -1196,6 +1196,23 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
}
#endif
void BKE_layer_collection_doversion_2_80(const Scene *scene, ViewLayer *view_layer)
{
LayerCollection *first_layer_collection = view_layer->layer_collections.first;
if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1 ||
first_layer_collection->collection != scene->master_collection) {
/* In some cases (from older files) we do have a master collection, but no matching layer,
* instead all the children of the master collection have their layer collections in the
* viewlayer's list. This is not a valid situation, add a layer for the master collection and
* add all existing first-level layers as children of that new master layer. */
ListBase layer_collections = view_layer->layer_collections;
BLI_listbase_clear(&view_layer->layer_collections);
LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
scene->master_collection);
master_layer_collection->layer_collections = layer_collections;
}
}
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
if (no_resync) {
@ -1208,21 +1225,24 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
}
if (BLI_listbase_is_empty(&view_layer->layer_collections)) {
/* In some cases (from older files) we do have a master collection, yet no matching layer.
* Create the master one here, so that the rest of the code can work as expected. */
/* In some cases (from older files, or when creating a new ViewLayer from
* #BKE_view_layer_add), we do have a master collection, yet no matching layer. Create the
* master one here, so that the rest of the code can work as expected. */
layer_collection_add(&view_layer->layer_collections, scene->master_collection);
}
else if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1) {
/* In some cases (from older files) we do have a master collection, but no matching layer,
* instead all the children of the master collection have their layer collections in the
* viewlayer's list. This is not a valid situation, add a layer for the master collection and
* add all existing first-level layers as children of that new master layer. */
ListBase layer_collections = view_layer->layer_collections;
BLI_listbase_clear(&view_layer->layer_collections);
LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
scene->master_collection);
master_layer_collection->layer_collections = layer_collections;
#ifndef NDEBUG
{
BLI_assert_msg(BLI_listbase_count_at_most(&view_layer->layer_collections, 2) == 1,
"ViewLayer's first level of children layer collections should always have "
"exactly one item");
LayerCollection *first_layer_collection = view_layer->layer_collections.first;
BLI_assert_msg(first_layer_collection->collection == scene->master_collection,
"ViewLayer's first layer collection should always be the one for the scene's "
"master collection");
}
#endif
/* Free cache. */
MEM_SAFE_FREE(view_layer->object_bases_array);

View File

@ -402,6 +402,8 @@ static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene)
do_version_layer_collection_pre(
view_layer, &view_layer->layer_collections, enabled_set, selectable_set);
BKE_layer_collection_doversion_2_80(scene, view_layer);
BKE_layer_collection_sync(scene, view_layer);
do_version_layer_collection_post(