Depsgraph: Optimize evaluation of dependencies of disabled modifiers
Solves long-standing issue when dependencies of disabled modifiers are evaluated. Simple test case: no drivers or animation. Manually enabling modifier is expected to bring FPS up, enabling modifier will bring FPS (sine evaluation can not be avoided) F13336690 More complex test case: modifier visibility is driven by an animated property. In am ideal world FPS during property being zero is fast and when property is 1 the FPS is low. F13336691. Differential Revision: https://developer.blender.org/D15625
This commit is contained in:
parent
cfbe11563a
commit
f12f7800c2
Notes:
blender-bot
2023-02-14 08:42:54 +01:00
Referenced by commit385bd0c4e9
, Fix T103685: Animation on objects that are disabled is ignored Referenced by commitc26d49e854
, Fix T101906: Modifier apply not working if target object is in excluded collection Referenced by issue #103685, Regression: Animation on objects that are disabled from render is ignored while Render Animation Referenced by issue #101906, Regression: Modifier apply not working if target object is in excluded collection Referenced by issue #101851, Regression: Duplicating a particle system crashes Blender Referenced by issue #100820, Regression: Crash when renaming a modifier when other modifier's visibility is driven by a driver Referenced by issue #100653, Reported object statistics are very wrong (under reported). Referenced by issue #100656, Rigid body/cloth simulation not occurring. Referenced by issue #100470, Regression: Changing the domain type from gas to liquid crashes Blender Referenced by issue #100394, Regression: Duplicating a modifier causes a crash
|
@ -13,6 +13,7 @@
|
|||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_stack.h"
|
||||
|
@ -95,6 +96,24 @@ bool DepsgraphBuilder::is_object_visibility_animated(const Object *object)
|
|||
return cache_->isPropertyAnimated(&object->id, property_id);
|
||||
}
|
||||
|
||||
bool DepsgraphBuilder::is_modifier_visibility_animated(const Object *object,
|
||||
const ModifierData *modifier)
|
||||
{
|
||||
AnimatedPropertyID property_id;
|
||||
if (graph_->mode == DAG_EVAL_VIEWPORT) {
|
||||
property_id = AnimatedPropertyID(
|
||||
&object->id, &RNA_Modifier, (void *)modifier, "show_viewport");
|
||||
}
|
||||
else if (graph_->mode == DAG_EVAL_RENDER) {
|
||||
property_id = AnimatedPropertyID(&object->id, &RNA_Modifier, (void *)modifier, "show_render");
|
||||
}
|
||||
else {
|
||||
BLI_assert_msg(0, "Unknown evaluation mode.");
|
||||
return false;
|
||||
}
|
||||
return cache_->isPropertyAnimated(&object->id, property_id);
|
||||
}
|
||||
|
||||
bool DepsgraphBuilder::check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan)
|
||||
{
|
||||
BLI_assert(object->type == OB_ARMATURE);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
struct Base;
|
||||
struct ID;
|
||||
struct Main;
|
||||
struct ModifierData;
|
||||
struct Object;
|
||||
struct bPoseChannel;
|
||||
|
||||
|
@ -25,6 +26,7 @@ class DepsgraphBuilder {
|
|||
virtual bool need_pull_base_into_graph(const Base *base);
|
||||
|
||||
virtual bool is_object_visibility_animated(const Object *object);
|
||||
virtual bool is_modifier_visibility_animated(const Object *object, const ModifierData *modifier);
|
||||
|
||||
virtual bool check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan);
|
||||
virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan);
|
||||
|
|
|
@ -879,9 +879,31 @@ void DepsgraphNodeBuilder::build_object_modifiers(Object *object)
|
|||
return;
|
||||
}
|
||||
|
||||
const ModifierMode modifier_mode = (graph_->mode == DAG_EVAL_VIEWPORT) ? eModifierMode_Realtime :
|
||||
eModifierMode_Render;
|
||||
|
||||
IDNode *id_node = find_id_node(&object->id);
|
||||
|
||||
add_operation_node(&object->id,
|
||||
NodeType::GEOMETRY,
|
||||
OperationCode::VISIBILITY,
|
||||
[id_node](::Depsgraph *depsgraph) {
|
||||
deg_evaluate_object_modifiers_mode_node_visibility(depsgraph, id_node);
|
||||
});
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, modifier, &object->modifiers) {
|
||||
add_operation_node(
|
||||
OperationNode *modifier_node = add_operation_node(
|
||||
&object->id, NodeType::GEOMETRY, OperationCode::MODIFIER, nullptr, modifier->name);
|
||||
|
||||
/* Mute modifier mode if the modifier is not enabled for the dependency graph mode.
|
||||
* This handles static (non-animated) mode of the modifier. */
|
||||
if ((modifier->mode & modifier_mode) == 0) {
|
||||
modifier_node->flag |= DEPSOP_FLAG_MUTE;
|
||||
}
|
||||
|
||||
if (is_modifier_visibility_animated(object, modifier)) {
|
||||
graph_->has_animated_visibility = true;
|
||||
}
|
||||
}
|
||||
|
||||
BuilderWalkUserData data;
|
||||
|
|
|
@ -877,6 +877,16 @@ void DepsgraphRelationBuilder::build_object_modifiers(Object *object)
|
|||
&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
|
||||
const OperationKey eval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
|
||||
|
||||
const ComponentKey object_visibility_key(&object->id, NodeType::VISIBILITY);
|
||||
const OperationKey modifier_visibility_key(
|
||||
&object->id, NodeType::GEOMETRY, OperationCode::VISIBILITY);
|
||||
add_relation(modifier_visibility_key,
|
||||
object_visibility_key,
|
||||
"modifier -> object visibility",
|
||||
RELATION_NO_VISIBILITY_CHANGE);
|
||||
|
||||
add_relation(modifier_visibility_key, eval_key, "modifier visibility -> geometry eval");
|
||||
|
||||
ModifierUpdateDepsgraphContext ctx = {};
|
||||
ctx.scene = scene_;
|
||||
ctx.object = object;
|
||||
|
|
|
@ -225,6 +225,10 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
|
|||
}
|
||||
return node_identifier;
|
||||
}
|
||||
|
||||
const char *prop_identifier = prop != nullptr ? RNA_property_identifier((PropertyRNA *)prop) :
|
||||
"";
|
||||
|
||||
if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
|
||||
const Object *object = reinterpret_cast<const Object *>(ptr->owner_id);
|
||||
const bConstraint *constraint = static_cast<const bConstraint *>(ptr->data);
|
||||
|
@ -264,6 +268,13 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
|
|||
return node_identifier;
|
||||
}
|
||||
}
|
||||
else if (RNA_struct_is_a(ptr->type, &RNA_Modifier) &&
|
||||
(contains(prop_identifier, "show_viewport") ||
|
||||
contains(prop_identifier, "show_render"))) {
|
||||
node_identifier.type = NodeType::GEOMETRY;
|
||||
node_identifier.operation_code = OperationCode::VISIBILITY;
|
||||
return node_identifier;
|
||||
}
|
||||
else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) ||
|
||||
RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) ||
|
||||
RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) ||
|
||||
|
@ -290,7 +301,6 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
|
|||
else if (ptr->type == &RNA_Object) {
|
||||
/* Transforms props? */
|
||||
if (prop != nullptr) {
|
||||
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
|
||||
/* TODO(sergey): How to optimize this? */
|
||||
if (contains(prop_identifier, "location") || contains(prop_identifier, "matrix_basis") ||
|
||||
contains(prop_identifier, "matrix_channel") ||
|
||||
|
|
|
@ -28,6 +28,8 @@ enum RelationFlag {
|
|||
RELATION_FLAG_GODMODE = (1 << 4),
|
||||
/* Relation will check existence before being added. */
|
||||
RELATION_CHECK_BEFORE_ADD = (1 << 5),
|
||||
/* The relation does not participate in visibility checks. */
|
||||
RELATION_NO_VISIBILITY_CHANGE = (1 << 6),
|
||||
};
|
||||
|
||||
/* B depends on A (A -> B) */
|
||||
|
|
|
@ -437,7 +437,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
|
|||
|
||||
evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::COPY_ON_WRITE);
|
||||
|
||||
if (graph->has_animated_visibility) {
|
||||
if (graph->has_animated_visibility || graph->need_update_nodes_visibility) {
|
||||
/* Update pending parents including only the ones which are affecting operations which are
|
||||
* affecting visibility. */
|
||||
state.need_update_pending_parents = true;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "intern/eval/deg_eval_visibility.h"
|
||||
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
|
@ -47,6 +48,38 @@ void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node
|
|||
}
|
||||
}
|
||||
|
||||
void deg_evaluate_object_modifiers_mode_node_visibility(::Depsgraph *depsgraph, IDNode *id_node)
|
||||
{
|
||||
BLI_assert(GS(id_node->id_cow->name) == ID_OB);
|
||||
|
||||
Depsgraph *graph = reinterpret_cast<Depsgraph *>(depsgraph);
|
||||
const Object *object = reinterpret_cast<const Object *>(id_node->id_cow);
|
||||
|
||||
DEG_debug_print_eval(depsgraph, __func__, object->id.name, &object->id);
|
||||
|
||||
if (BLI_listbase_is_empty(&object->modifiers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ModifierMode modifier_mode = (graph->mode == DAG_EVAL_VIEWPORT) ? eModifierMode_Realtime :
|
||||
eModifierMode_Render;
|
||||
|
||||
const ComponentNode *geometry_component = id_node->find_component(NodeType::GEOMETRY);
|
||||
LISTBASE_FOREACH (ModifierData *, modifier, &object->modifiers) {
|
||||
OperationNode *modifier_node = geometry_component->find_operation(OperationCode::MODIFIER,
|
||||
modifier->name);
|
||||
|
||||
const bool modifier_enabled = modifier->mode & modifier_mode;
|
||||
const int mute_flag = modifier_enabled ? 0 : DEPSOP_FLAG_MUTE;
|
||||
if ((modifier_node->flag & DEPSOP_FLAG_MUTE) != mute_flag) {
|
||||
modifier_node->flag &= ~DEPSOP_FLAG_MUTE;
|
||||
modifier_node->flag |= mute_flag;
|
||||
|
||||
graph->need_update_nodes_visibility = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deg_graph_flush_visibility_flags(Depsgraph *graph)
|
||||
{
|
||||
enum {
|
||||
|
@ -116,11 +149,31 @@ void deg_graph_flush_visibility_flags(Depsgraph *graph)
|
|||
OperationNode *op_from = reinterpret_cast<OperationNode *>(rel->from);
|
||||
ComponentNode *comp_from = op_from->owner;
|
||||
|
||||
const bool target_possibly_affects_visible_id = comp_to->possibly_affects_visible_id;
|
||||
const bool target_affects_visible_id = comp_to->affects_visible_id;
|
||||
|
||||
op_from->flag |= (op_to->flag & OperationFlag::DEPSOP_FLAG_AFFECTS_VISIBILITY);
|
||||
|
||||
if (rel->flag & RELATION_NO_VISIBILITY_CHANGE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool target_possibly_affects_visible_id = comp_to->possibly_affects_visible_id;
|
||||
|
||||
bool target_affects_visible_id = comp_to->affects_visible_id;
|
||||
|
||||
/* This is a bit arbitrary but the idea here is following:
|
||||
*
|
||||
* - When another object is used by a disabled modifier we do not want that object to
|
||||
* be considered needed for evaluation.
|
||||
*
|
||||
* - However, we do not want to take mute flag during visibility propagation within the
|
||||
* same object. Otherwise drivers and transform dependencies of the geometry component
|
||||
* entry component might not be properly handled.
|
||||
*
|
||||
* This code works fine for muting modifiers, but might need tweaks when mute is used for
|
||||
* something else. */
|
||||
if (comp_from != comp_to && (op_to->flag & DEPSOP_FLAG_MUTE)) {
|
||||
target_affects_visible_id = false;
|
||||
}
|
||||
|
||||
/* Visibility component forces all components of the current ID to be considered as
|
||||
* affecting directly visible. */
|
||||
if (comp_from->type == NodeType::VISIBILITY) {
|
||||
|
|
|
@ -18,6 +18,9 @@ struct IDNode;
|
|||
* restriction flags. */
|
||||
void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node);
|
||||
|
||||
/* Update node visibility flags based on actual modifiers mode flags. */
|
||||
void deg_evaluate_object_modifiers_mode_node_visibility(::Depsgraph *depsgraph, IDNode *id_node);
|
||||
|
||||
/* Flush both static and dynamic visibility flags from leaves up to the roots, making it possible
|
||||
* to know whether a node has affect on something (potentially) visible. */
|
||||
void deg_graph_flush_visibility_flags(Depsgraph *graph);
|
||||
|
|
|
@ -227,6 +227,16 @@ void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source)
|
|||
* the evaluated clues that evaluation needs to happen again. */
|
||||
graph->add_entry_tag(this);
|
||||
|
||||
/* Enforce dynamic visibility codepath update.
|
||||
* This ensures visibility flags are consistently propagated throughout the dependency graph when
|
||||
* there is no animated visibility in the graph.
|
||||
*
|
||||
* For example this ensures that graph is updated properly when manually toggling non-animated
|
||||
* modifier visibility. */
|
||||
if (opcode == OperationCode::VISIBILITY) {
|
||||
graph->need_update_nodes_visibility = true;
|
||||
}
|
||||
|
||||
/* Tag for update, but also note that this was the source of an update. */
|
||||
flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
|
||||
switch (source) {
|
||||
|
|
|
@ -219,6 +219,9 @@ enum OperationFlag {
|
|||
/* The operation directly or indirectly affects ID node visibility. */
|
||||
DEPSOP_FLAG_AFFECTS_VISIBILITY = (1 << 4),
|
||||
|
||||
/* Evaluation of the node is temporarily disabled. */
|
||||
DEPSOP_FLAG_MUTE = (1 << 5),
|
||||
|
||||
/* Set of flags which gets flushed along the relations. */
|
||||
DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue