Fix further (unreported) issues in object collection cache cleanup code.

`BKE_collection_object_cache_free` can be called from some points in
code (e.g. during ID remapping) where proper parenting relationships
between collections cannot be ensured.

Would be good to check if recursive cache cleanup is actually needed
from these points, it would almost certainly be better and safer to
instead tag parent collections as dirty too, but this will be for
another time.

For now, just add a NULL-check on the parent collection pointer.
This commit is contained in:
Bastien Montagne
2023-04-25 14:00:16 +02:00
parent 250d35928e
commit b666d2d1bd

View File

@@ -887,21 +887,33 @@ ListBase BKE_collection_object_cache_instanced_get(Collection *collection)
static void collection_object_cache_free(Collection *collection)
{
/* Clear own cache an for all parents, since those are affected by changes as well. */
collection->flag &= ~(COLLECTION_HAS_OBJECT_CACHE | COLLECTION_HAS_OBJECT_CACHE_INSTANCED);
BLI_freelistN(&collection->runtime.object_cache);
BLI_freelistN(&collection->runtime.object_cache_instanced);
}
void BKE_collection_object_cache_free(Collection *collection)
static void collection_object_cache_free_parent_recursive(Collection *collection)
{
collection_object_cache_free(collection);
/* Clear cache in all parents recursively, since those are affected by changes as well. */
LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime.parents) {
BKE_collection_object_cache_free(parent->collection);
/* In theory there should be no NULL pointer here. However, this code can be called from
* non-valid temporary states (e.g. indirectly from #BKE_collections_object_remove_invalids
* as part of ID remapping process). */
if (parent->collection == NULL) {
continue;
}
collection_object_cache_free_parent_recursive(parent->collection);
}
}
void BKE_collection_object_cache_free(Collection *collection)
{
BLI_assert(collection != NULL);
collection_object_cache_free_parent_recursive(collection);
}
void BKE_main_collections_object_cache_free(const Main *bmain)
{
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {