Despgraph: Keep track of per-component visibility
The idea of those flags is to avoid evaluation of operations which are not needed to bring visible objects to an up to date state. Previously, dependency graph attempted to do combine those into an ID level flag. In practice it proved to be rather tricky, since there could be dependency cycles on ID level which will not exist on component level.
This commit is contained in:
parent
cc061d349b
commit
afb4da6650
Notes:
blender-bot
2023-02-14 00:20:15 +01:00
Referenced by commit ed386507e1
, Fix T74984: Crash opening specific production files
|
@ -34,6 +34,8 @@
|
|||
#include "DNA_object_types.h"
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_stack.h"
|
||||
|
||||
extern "C" {
|
||||
|
@ -64,6 +66,13 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
|
|||
|
||||
BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode *),
|
||||
"DEG flush layers stack");
|
||||
foreach (IDDepsNode *id_node, graph->id_nodes) {
|
||||
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
|
||||
{
|
||||
comp_node->affects_directly_visible = id_node->is_directly_visible;
|
||||
}
|
||||
GHASH_FOREACH_END();
|
||||
}
|
||||
foreach (OperationDepsNode *op_node, graph->operations) {
|
||||
op_node->custom_flags = 0;
|
||||
op_node->num_links_pending = 0;
|
||||
|
@ -86,8 +95,8 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
|
|||
foreach (DepsRelation *rel, op_node->inlinks) {
|
||||
if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
|
||||
OperationDepsNode *op_from = (OperationDepsNode *)rel->from;
|
||||
op_from->owner->owner->is_visible |=
|
||||
op_node->owner->owner->is_visible;
|
||||
op_from->owner->affects_directly_visible |=
|
||||
op_node->owner->affects_directly_visible;
|
||||
}
|
||||
}
|
||||
/* Schedule parent nodes. */
|
||||
|
|
|
@ -163,16 +163,16 @@ IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
|
|||
{
|
||||
IDDepsNode *id_node = NULL;
|
||||
ID *id_cow = NULL;
|
||||
bool is_previous_visible = false;
|
||||
bool is_previous_directly_visible = false;
|
||||
IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id);
|
||||
if (id_info != NULL) {
|
||||
id_cow = id_info->id_cow;
|
||||
is_previous_visible = id_info->is_visible;
|
||||
is_previous_directly_visible = id_info->is_directly_visible;
|
||||
/* Tag ID info to not free the CoW ID pointer. */
|
||||
id_info->id_cow = NULL;
|
||||
}
|
||||
id_node = graph_->add_id_node(id, id_cow);
|
||||
id_node->is_previous_visible = is_previous_visible;
|
||||
id_node->is_previous_directly_visible = is_previous_directly_visible;
|
||||
/* Currently all ID nodes are supposed to have copy-on-write logic.
|
||||
*
|
||||
* NOTE: Zero number of components indicates that ID node was just created.
|
||||
|
@ -352,7 +352,7 @@ void DepsgraphNodeBuilder::begin_build()
|
|||
else {
|
||||
id_info->id_cow = NULL;
|
||||
}
|
||||
id_info->is_visible = id_node->is_visible;
|
||||
id_info->is_directly_visible = id_node->is_directly_visible;
|
||||
BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info);
|
||||
id_node->id_cow = NULL;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
|
|||
!is_collection_restricted && is_parent_collection_visible_;
|
||||
if (built_map_.checkIsBuiltAndTag(collection)) {
|
||||
IDDepsNode *id_node = find_id_node(&collection->id);
|
||||
if (is_collection_visible && !id_node->is_visible) {
|
||||
if (is_collection_visible && !id_node->is_directly_visible) {
|
||||
/* Collection became visible, make sure nested collections and
|
||||
* objects are poked with the new visibility flag, since they
|
||||
* might become visible too.
|
||||
|
@ -502,7 +502,7 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
|
|||
else {
|
||||
/* Collection itself. */
|
||||
IDDepsNode *id_node = add_id_node(&collection->id);
|
||||
id_node->is_visible = is_collection_visible;
|
||||
id_node->is_directly_visible = is_collection_visible;
|
||||
}
|
||||
/* Backup state. */
|
||||
Collection *current_state_collection = collection_;
|
||||
|
@ -541,13 +541,20 @@ void DepsgraphNodeBuilder::build_object(int base_index,
|
|||
build_object_flags(base_index, object, linked_state);
|
||||
}
|
||||
id_node->linked_state = max(id_node->linked_state, linked_state);
|
||||
id_node->is_visible |= is_visible;
|
||||
if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) {
|
||||
id_node->is_directly_visible |= is_visible;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Create ID node for object and begin init. */
|
||||
IDDepsNode *id_node = add_id_node(&object->id);
|
||||
id_node->linked_state = linked_state;
|
||||
id_node->is_visible = is_visible;
|
||||
if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) {
|
||||
id_node->is_directly_visible = is_visible;
|
||||
}
|
||||
else {
|
||||
id_node->is_directly_visible = false;
|
||||
}
|
||||
object->customdata_mask = 0;
|
||||
/* Various flags, flushing from bases/collections. */
|
||||
build_object_flags(base_index, object, linked_state);
|
||||
|
|
|
@ -228,7 +228,7 @@ struct DepsgraphNodeBuilder {
|
|||
/* State of the is_visible from ID node from previous state of the
|
||||
* dependency graph.
|
||||
*/
|
||||
bool is_visible;
|
||||
bool is_directly_visible;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
|
@ -163,7 +163,7 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
|
|||
/* Set it early in case we need to exit and we are running from within a loop. */
|
||||
iter->skip = true;
|
||||
|
||||
if (!id_node->is_visible) {
|
||||
if (!id_node->is_directly_visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node,
|
|||
{
|
||||
ID *id_cow = id_node->id_cow;
|
||||
|
||||
if (!id_node->is_visible) {
|
||||
if (!id_node->is_directly_visible) {
|
||||
iter->skip = true;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -485,14 +485,17 @@ void deg_id_tag_update(Main *bmain, ID *id, int flag)
|
|||
|
||||
void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
|
||||
{
|
||||
/* TODO(sergey): We might want to tag components which did not affect
|
||||
* anything visible before new objects became visible.
|
||||
*/
|
||||
foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
|
||||
if (!id_node->is_visible) {
|
||||
if (!id_node->is_directly_visible) {
|
||||
/* ID is not visible within the current dependency graph, no need
|
||||
* botherwith it to tag or anything.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (id_node->is_previous_visible) {
|
||||
if (id_node->is_previous_directly_visible) {
|
||||
/* The ID was already visible and evaluated, all the subsequent
|
||||
* updates and tags are to be done explicitly.
|
||||
*/
|
||||
|
@ -527,7 +530,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
|
|||
* tags we request from here will be applied in the updated state of
|
||||
* dependency graph.
|
||||
*/
|
||||
id_node->is_previous_visible = true;
|
||||
id_node->is_previous_directly_visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,8 +112,7 @@ static bool check_operation_node_visible(OperationDepsNode *op_node)
|
|||
if (comp_node->type == DEG_NODE_TYPE_COPY_ON_WRITE) {
|
||||
return true;
|
||||
}
|
||||
const IDDepsNode *id_node = comp_node->owner;
|
||||
return id_node->is_visible;
|
||||
return comp_node->affects_directly_visible;
|
||||
}
|
||||
|
||||
static void calculate_pending_func(
|
||||
|
|
|
@ -124,7 +124,8 @@ static void comp_node_hash_value_free(void *value_v)
|
|||
|
||||
ComponentDepsNode::ComponentDepsNode() :
|
||||
entry_operation(NULL),
|
||||
exit_operation(NULL)
|
||||
exit_operation(NULL),
|
||||
affects_directly_visible(false)
|
||||
{
|
||||
operations_map = BLI_ghash_new(comp_node_hash_key,
|
||||
comp_node_hash_key_cmp,
|
||||
|
|
|
@ -150,6 +150,11 @@ struct ComponentDepsNode : public DepsNode {
|
|||
* is tagged for update.
|
||||
*/
|
||||
virtual bool need_tag_cow_before_update() { return true; }
|
||||
|
||||
/* Denotes whether this component affects (possibly indirectly) on a
|
||||
* directly visible object.
|
||||
*/
|
||||
bool affects_directly_visible;
|
||||
};
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
|
|
@ -104,8 +104,8 @@ void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
|
|||
id_orig = (ID *)id;
|
||||
eval_flags = 0;
|
||||
linked_state = DEG_ID_LINKED_INDIRECTLY;
|
||||
is_visible = true;
|
||||
is_previous_visible = false;
|
||||
is_directly_visible = true;
|
||||
is_previous_directly_visible = false;
|
||||
|
||||
components = BLI_ghash_new(id_deps_node_hash_key,
|
||||
id_deps_node_hash_key_cmp,
|
||||
|
@ -174,7 +174,8 @@ string IDDepsNode::identifier() const
|
|||
BLI_snprintf(cow_ptr, sizeof(cow_ptr), "%p", id_cow);
|
||||
return string(nodeTypeAsString(type)) + " : " + name +
|
||||
" (orig: " + orig_ptr + ", eval: " + cow_ptr +
|
||||
", is_visible " + (is_visible ? "true" : "false") + ")";
|
||||
", is_directly_visible " + (is_directly_visible ? "true"
|
||||
: "false") + ")";
|
||||
}
|
||||
|
||||
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
|
||||
|
|
|
@ -77,17 +77,15 @@ struct IDDepsNode : public DepsNode {
|
|||
|
||||
eDepsNode_LinkedState_Type linked_state;
|
||||
|
||||
/* Indicates the datablock is visible, meaning, it is to be evaluated by
|
||||
* the dependency graph.
|
||||
*/
|
||||
bool is_visible;
|
||||
/* Indicates the datablock is visible in the evaluated scene. */
|
||||
bool is_directly_visible;
|
||||
/* Is used to detect when ID becomes visible within a dependency graph,
|
||||
* this value equals to:
|
||||
* - False if the ID was never inside of the dependency graph.
|
||||
* - Value if is_visible of ID node from the previous state of the
|
||||
* dependency graph.
|
||||
*/
|
||||
bool is_previous_visible;
|
||||
bool is_previous_directly_visible;
|
||||
|
||||
DEG_DEPSNODE_DECLARE;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue