Depsgraph: Save memory by ignoring invisible objects

This finished old standing TODO which was attempting to
ignore objects of all invisible collections.

The difference here is that we remove invisible bases from
view layers. This guarantees that the evaluated state is
consistent and does not reference original objects.
This commit is contained in:
2018-11-14 16:50:59 +01:00
parent 156fe74f91
commit 773110f848
10 changed files with 143 additions and 35 deletions

View File

@@ -1425,8 +1425,9 @@ void BKE_layer_eval_view_layer(
/* Visibility based on depsgraph mode. */
const eEvaluationMode mode = DEG_get_mode(depsgraph);
const int base_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
const int base_visible_flag = (mode == DAG_EVAL_VIEWPORT)
? BASE_ENABLED_VIEWPORT
: BASE_ENABLED_RENDER;
/* Create array of bases, for fast index-based lookup. */
const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
MEM_SAFE_FREE(view_layer->object_bases_array);
@@ -1435,9 +1436,8 @@ void BKE_layer_eval_view_layer(
int base_index = 0;
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
/* Compute visibility for depsgraph evaluation mode. */
if (base->flag & base_flag) {
if (base->flag & base_visible_flag) {
base->flag |= BASE_ENABLED | BASE_VISIBLE;
if (mode == DAG_EVAL_VIEWPORT && (base->flag & BASE_HIDDEN)) {
base->flag &= ~BASE_VISIBLE;
}
@@ -1445,24 +1445,23 @@ void BKE_layer_eval_view_layer(
else {
base->flag &= ~(BASE_ENABLED | BASE_VISIBLE | BASE_SELECTABLE);
}
/* If base is not selectabled, clear select. */
if ((base->flag & BASE_SELECTABLE) == 0) {
base->flag &= ~BASE_SELECTED;
}
view_layer->object_bases_array[base_index++] = base;
}
/* Flush back base flag to the original view layer for editing. */
if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) {
ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph);
Base *base_orig = view_layer_orig->object_bases.first;
const Base *base_eval = view_layer->object_bases.first;
while (base_orig != NULL) {
base_orig->flag = base_eval->flag;
if (base_orig->flag & base_visible_flag) {
base_orig->flag = base_eval->flag;
base_eval = base_eval->next;
}
base_orig = base_orig->next;
base_eval = base_eval->next;
}
}
}

View File

@@ -419,7 +419,7 @@ void DepsgraphNodeBuilder::build_id(ID *id)
build_camera((Camera *)id);
break;
case ID_GR:
build_collection((Collection *)id);
build_collection(NULL, (Collection *)id);
break;
case ID_OB:
/* TODO(sergey): Get visibility from a "parent" somehow.
@@ -489,7 +489,9 @@ void DepsgraphNodeBuilder::build_id(ID *id)
}
}
void DepsgraphNodeBuilder::build_collection(Collection *collection)
void DepsgraphNodeBuilder::build_collection(
LayerCollection *from_layer_collection,
Collection *collection)
{
const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT)
? COLLECTION_RESTRICT_VIEW
@@ -497,13 +499,16 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
const bool is_collection_restricted = (collection->flag & restrict_flag);
const bool is_collection_visible =
!is_collection_restricted && is_parent_collection_visible_;
IDDepsNode *id_node;
if (built_map_.checkIsBuiltAndTag(collection)) {
IDDepsNode *id_node = find_id_node(&collection->id);
if (is_collection_visible && !id_node->is_directly_visible) {
id_node = find_id_node(&collection->id);
if (is_collection_visible &&
id_node->is_directly_visible == false &&
id_node->is_collection_fully_expanded == true)
{
/* Collection became visible, make sure nested collections and
* objects are poked with the new visibility flag, since they
* might become visible too.
*/
* might become visible too. */
}
else {
return;
@@ -511,9 +516,14 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
}
else {
/* Collection itself. */
IDDepsNode *id_node = add_id_node(&collection->id);
id_node = add_id_node(&collection->id);
id_node->is_directly_visible = is_collection_visible;
}
if (from_layer_collection != NULL) {
/* If we came from layer collection we don't go deeper, view layer
* builder takes care of going deeper. */
return;
}
/* Backup state. */
Collection *current_state_collection = collection_;
const bool is_current_parent_collection_visible =
@@ -528,11 +538,12 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
}
/* Build child collections. */
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
build_collection(child->collection);
build_collection(NULL, child->collection);
}
/* Restore state. */
collection_ = current_state_collection;
is_parent_collection_visible_ = is_current_parent_collection_visible;
id_node->is_collection_fully_expanded = true;
}
void DepsgraphNodeBuilder::build_object(int base_index,
@@ -635,7 +646,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
const bool is_current_parent_collection_visible =
is_parent_collection_visible_;
is_parent_collection_visible_ = is_visible;
build_collection(object->dup_group);
build_collection(NULL, object->dup_group);
is_parent_collection_visible_ = is_current_parent_collection_visible;
add_operation_node(&object->id,
DEG_NODE_TYPE_DUPLI,
@@ -1059,7 +1070,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
build_collection(rbw->group);
build_collection(NULL, rbw->group);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
{
@@ -1137,7 +1148,7 @@ void DepsgraphNodeBuilder::build_particles(Object *object,
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
build_collection(part->dup_group);
build_collection(NULL, part->dup_group);
}
break;
}

View File

@@ -165,7 +165,8 @@ struct DepsgraphNodeBuilder {
void build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state);
void build_collection(Collection *collection);
void build_collection(LayerCollection *from_layer_collection,
Collection *collection);
void build_object(int base_index,
Object *object,
eDepsNode_LinkedState_Type linked_state,

View File

@@ -75,7 +75,7 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb)
continue;
}
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
build_collection(lc->collection);
build_collection(lc, lc->collection);
}
build_layer_collections(&lc->layer_collections);
}
@@ -86,8 +86,9 @@ void DepsgraphNodeBuilder::build_view_layer(
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state)
{
view_layer_index_ = BLI_findindex(&scene->view_layers, view_layer);
BLI_assert(view_layer_index_ != -1);
/* NOTE: Pass view layer index of 0 since after scene CoW there is
* only one view layer in there. */
view_layer_index_ = 0;
/* Scene ID block. */
add_id_node(&scene->id);
/* Time source. */
@@ -109,9 +110,14 @@ void DepsgraphNodeBuilder::build_view_layer(
LISTBASE_FOREACH(Base *, base, &view_layer->object_bases) {
/* object itself */
const bool is_object_visible = (base->flag & base_flag);
build_object(base_index, base->object, linked_state, is_object_visible);
if (is_object_visible) {
build_object(base_index,
base->object,
linked_state,
is_object_visible);
++base_index;
}
base->object->select_color = select_color++;
++base_index;
}
build_layer_collections(&view_layer->layer_collections);
if (scene->camera != NULL) {

View File

@@ -434,7 +434,7 @@ void DepsgraphRelationBuilder::build_id(ID *id)
build_camera((Camera *)id);
break;
case ID_GR:
build_collection(NULL, (Collection *)id);
build_collection(NULL, NULL, (Collection *)id);
break;
case ID_OB:
build_object(NULL, (Object *)id);
@@ -486,9 +486,19 @@ void DepsgraphRelationBuilder::build_id(ID *id)
}
void DepsgraphRelationBuilder::build_collection(
LayerCollection *from_layer_collection,
Object *object,
Collection *collection)
{
if (from_layer_collection != NULL) {
/* If we came from layer collection we don't go deeper, view layer
* builder takes care of going deeper.
*
* NOTE: Do early output before tagging build as done, so possbile
* subsequent builds from outside of the layer collection properly
* recurses into all the nested objects and collections. */
return;
}
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != NULL ? &object->id : NULL,
DEG_NODE_TYPE_TRANSFORM,
@@ -500,7 +510,7 @@ void DepsgraphRelationBuilder::build_collection(
build_object(NULL, cob->ob);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
build_collection(NULL, child->collection);
build_collection(NULL, NULL, child->collection);
}
}
if (object != NULL) {
@@ -644,7 +654,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
}
/* Object dupligroup. */
if (object->dup_group != NULL) {
build_collection(object, object->dup_group);
build_collection(NULL, object, object->dup_group);
}
/* Point caches. */
build_object_pointcache(object);
@@ -1576,7 +1586,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
build_collection(NULL, rbw->group);
build_collection(NULL, NULL, rbw->group);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
{
@@ -1758,7 +1768,7 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
build_collection(NULL, part->dup_group);
build_collection(NULL, NULL, part->dup_group);
LISTBASE_FOREACH (CollectionObject *, go, &part->dup_group->gobject) {
build_particles_visualization_object(object,
psys,

View File

@@ -206,7 +206,9 @@ struct DepsgraphRelationBuilder
void build_id(ID *id);
void build_layer_collections(ListBase *lb);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
void build_collection(Object *object, Collection *collection);
void build_collection(LayerCollection *from_layer_collection,
Object *object,
Collection *collection);
void build_object(Base *base, Object *object);
void build_object_flags(Base *base, Object *object);
void build_object_data(Object *object);

View File

@@ -79,7 +79,7 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
continue;
}
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
build_collection(NULL, lc->collection);
build_collection(lc, NULL, lc->collection);
}
build_layer_collections(&lc->layer_collections);
}
@@ -94,8 +94,13 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
* passed to the evaluation functions. During relations builder we only
* do NULL-pointer check of the base, so it's fine to pass original one.
*/
const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
build_object(base, base->object);
const bool is_object_visible = (base->flag & base_flag);
if (is_object_visible) {
build_object(base, base->object);
}
}
build_layer_collections(&view_layer->layer_collections);

View File

@@ -57,6 +57,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "MEM_guardedalloc.h"
@@ -326,6 +327,71 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
return result;
}
/* Remove all view layers but the one which corresponds to an input one. */
void scene_remove_unused_view_layers(const Depsgraph *depsgraph,
Scene *scene_cow)
{
ViewLayer *view_layer_input = depsgraph->view_layer;
ViewLayer *view_layer_eval = NULL;
/* Find evaluated view layer. At the same time we free memory used by
* all other of the view layers. */
for (ViewLayer *view_layer_cow =
reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first),
*view_layer_next;
view_layer_cow != NULL;
view_layer_cow = view_layer_next)
{
view_layer_next = view_layer_cow->next;
if (STREQ(view_layer_input->name, view_layer_cow->name)) {
view_layer_eval = view_layer_cow;
}
else {
BKE_view_layer_free_ex(view_layer_cow, false);
}
}
BLI_assert(view_layer_eval != NULL);
/* Make evaluated view layer the only one in the evaluated scene. */
view_layer_eval->prev = view_layer_eval->next = NULL;
scene_cow->view_layers.first = view_layer_eval;
scene_cow->view_layers.last = view_layer_eval;
}
/* Makes it so given view layer only has bases corresponding to a visible
* objects. */
void view_layer_remove_invisible_bases(const Depsgraph *depsgraph,
ViewLayer *view_layer)
{
const int base_visible_flag = (depsgraph->mode == DAG_EVAL_VIEWPORT) ?
BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
ListBase visible_bases = {NULL, NULL};
for (Base *base = reinterpret_cast<Base *>(view_layer->object_bases.first),
*base_next;
base != NULL;
base = base_next)
{
base_next = base->next;
const bool is_object_visible = (base->flag & base_visible_flag);
if (is_object_visible) {
BLI_addtail(&visible_bases, base);
}
else {
MEM_freeN(base);
}
}
view_layer->object_bases = visible_bases;
}
void scene_cleanup_view_layers(const Depsgraph *depsgraph, Scene *scene_cow)
{
scene_remove_unused_view_layers(depsgraph, scene_cow);
view_layer_remove_invisible_bases(
depsgraph,
reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first));
/* TODO(sergey): Remove objects from collections as well.
* Not a HUGE deal for now, nobody is looking into those CURRENTLY.
* Still not an excuse to have those. */
}
/* Check whether given ID is expanded or still a shallow copy. */
BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
{
@@ -338,7 +404,7 @@ BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
* TODO(sergey): How to make it more robust for the future, so we don't have
* to maintain exception lists all over the code?
*/
static bool check_datablocks_copy_on_writable(const ID *id_orig)
bool check_datablocks_copy_on_writable(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
/* We shouldn't bother if copied ID is same as original one. */
@@ -643,6 +709,9 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
case ID_SCE:
{
done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow);
if (done) {
scene_cleanup_view_layers(depsgraph, (Scene *)id_cow);
}
break;
}
case ID_ME:

View File

@@ -106,6 +106,7 @@ void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
previous_eval_flags = 0;
linked_state = DEG_ID_LINKED_INDIRECTLY;
is_directly_visible = true;
is_collection_fully_expanded = false;
visible_components_mask = 0;
previously_visible_components_mask = 0;

View File

@@ -86,6 +86,10 @@ struct IDDepsNode : public DepsNode {
/* Indicates the datablock is visible in the evaluated scene. */
bool is_directly_visible;
/* For the collection type of ID, denotes whether collection was fully
* recursed into. */
bool is_collection_fully_expanded;
IDComponentsMask visible_components_mask;
IDComponentsMask previously_visible_components_mask;