Blender V5.0
deg_eval_visibility.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10
11#include "DNA_layer_types.h"
12#include "DNA_modifier_types.h"
13#include "DNA_object_types.h"
14
15#include "BLI_assert.h"
16#include "BLI_listbase.h"
17#include "BLI_stack.hh"
18
19#include "DEG_depsgraph.hh"
20
21#include "intern/depsgraph.hh"
27
28namespace blender::deg {
29
31{
32 BLI_assert(GS(id_node->id_cow->name) == ID_OB);
33
34 Depsgraph *graph = reinterpret_cast<Depsgraph *>(depsgraph);
35 const Object *object = reinterpret_cast<const Object *>(id_node->id_cow);
36
37 DEG_debug_print_eval(depsgraph, __func__, object->id.name, &object->id);
38
39 const int required_flags = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT :
41
42 const bool is_enabled = !graph->use_visibility_optimization ||
43 object->base_flag & required_flags;
44
45 if (id_node->is_enabled_on_eval != is_enabled) {
46 id_node->is_enabled_on_eval = is_enabled;
47
48 /* Tag dependency graph for changed visibility, so that it is updated on all dependencies prior
49 * to a pass of an actual evaluation. */
50 graph->need_update_nodes_visibility = true;
51 }
52}
53
55{
56 BLI_assert(GS(id_node->id_cow->name) == ID_OB);
57
58 Depsgraph *graph = reinterpret_cast<Depsgraph *>(depsgraph);
59 const Object *object = reinterpret_cast<const Object *>(id_node->id_cow);
60
61 DEG_debug_print_eval(depsgraph, __func__, object->id.name, &object->id);
62
63 if (BLI_listbase_is_empty(&object->modifiers)) {
64 return;
65 }
66
67 const ModifierMode modifier_mode = (graph->mode == DAG_EVAL_VIEWPORT) ? eModifierMode_Realtime :
69
70 const ComponentNode *geometry_component = id_node->find_component(NodeType::GEOMETRY);
72 OperationNode *modifier_node = geometry_component->find_operation(OperationCode::MODIFIER,
73 modifier->name);
74
75 BLI_assert_msg(modifier_node != nullptr,
76 "Modifier node in depsgraph is not found. Likely due to missing "
77 "DEG_relations_tag_update().");
78
79 const bool modifier_enabled = !graph->use_visibility_optimization ||
80 (modifier->mode & modifier_mode);
81 const int mute_flag = modifier_enabled ? 0 : DEPSOP_FLAG_MUTE;
82 if ((modifier_node->flag & DEPSOP_FLAG_MUTE) != mute_flag) {
83 modifier_node->flag &= ~DEPSOP_FLAG_MUTE;
84 modifier_node->flag |= mute_flag;
85
86 graph->need_update_nodes_visibility = true;
87 }
88 }
89}
90
92{
93 enum {
94 DEG_NODE_VISITED = (1 << 0),
95 };
96
97 for (IDNode *id_node : graph->id_nodes) {
98 for (ComponentNode *comp_node : id_node->components.values()) {
99 comp_node->possibly_affects_visible_id = id_node->is_visible_on_build;
100 comp_node->affects_visible_id = id_node->is_visible_on_build && id_node->is_enabled_on_eval;
101
102 /* Visibility component is always to be considered to have the same visibility as the
103 * `id_node->is_visible_on_build`. This is because the visibility is to be evaluated
104 * regardless of its current state as it might get changed due to animation. */
105 if (comp_node->type == NodeType::VISIBILITY) {
106 comp_node->affects_visible_id = id_node->is_visible_on_build;
107 }
108
109 /* Enforce "visibility" of the synchronization component.
110 *
111 * This component is never connected to other ID nodes, and hence can not be handled in the
112 * same way as other components needed for evaluation. It is only needed for proper
113 * evaluation of the ID node it belongs to.
114 *
115 * The design is such that the synchronization is supposed to happen whenever any part of the
116 * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag
117 * flushing and scheduling will handle the component in a generic manner. */
118 if (comp_node->type == NodeType::SYNCHRONIZATION) {
119 comp_node->possibly_affects_visible_id = true;
120 comp_node->affects_visible_id = true;
121 }
122 }
123 }
124
126
127 for (OperationNode *op_node : graph->operations) {
128 op_node->custom_flags = 0;
129 op_node->num_links_pending = 0;
130 for (Relation *rel : op_node->outlinks) {
131 if ((rel->to->type == NodeType::OPERATION) && (rel->flag & RELATION_FLAG_CYCLIC) == 0) {
132 ++op_node->num_links_pending;
133 }
134 }
135 if (op_node->num_links_pending == 0) {
136 stack.push(op_node);
137 op_node->custom_flags |= DEG_NODE_VISITED;
138 }
139 }
140
141 while (!stack.is_empty()) {
142 OperationNode *op_node = stack.pop();
143
144 /* Flush flags to parents. */
145 for (Relation *rel : op_node->inlinks) {
146 if (rel->from->type == NodeType::OPERATION) {
147 const OperationNode *op_to = reinterpret_cast<const OperationNode *>(rel->to);
148 const ComponentNode *comp_to = op_to->owner;
149
150 /* Ignore the synchronization target.
151 * It is always visible and should not affect on other components. */
152 if (comp_to->type == NodeType::SYNCHRONIZATION) {
153 continue;
154 }
155
156 OperationNode *op_from = reinterpret_cast<OperationNode *>(rel->from);
157 ComponentNode *comp_from = op_from->owner;
158
160
162 continue;
163 }
164
165 const bool target_possibly_affects_visible_id = comp_to->possibly_affects_visible_id;
166
167 bool target_affects_visible_id = comp_to->affects_visible_id;
168
169 /* This is a bit arbitrary but the idea here is following:
170 *
171 * - When another object is used by a disabled modifier we do not want that object to
172 * be considered needed for evaluation.
173 *
174 * - However, we do not want to take mute flag during visibility propagation within the
175 * same object. Otherwise drivers and transform dependencies of the geometry component
176 * entry component might not be properly handled.
177 *
178 * This code works fine for muting modifiers, but might need tweaks when mute is used for
179 * something else. */
180 if (comp_from != comp_to && (op_to->flag & DEPSOP_FLAG_MUTE)) {
181 target_affects_visible_id = false;
182 }
183
184 /* Visibility component forces all components of the current ID to be considered as
185 * affecting directly visible. */
186 if (comp_from->type == NodeType::VISIBILITY) {
187 const IDNode *id_node_from = comp_from->owner;
188 if (target_possibly_affects_visible_id) {
189 for (ComponentNode *comp_node : id_node_from->components.values()) {
190 comp_node->possibly_affects_visible_id |= target_possibly_affects_visible_id;
191 }
192 }
193 if (target_affects_visible_id) {
194 for (ComponentNode *comp_node : id_node_from->components.values()) {
195 comp_node->affects_visible_id |= target_affects_visible_id;
196 }
197 }
198 }
199 else {
200 comp_from->possibly_affects_visible_id |= target_possibly_affects_visible_id;
201 comp_from->affects_visible_id |= target_affects_visible_id;
202 }
203 }
204 }
205
206 /* Schedule parent nodes. */
207 for (Relation *rel : op_node->inlinks) {
208 if (rel->from->type == NodeType::OPERATION) {
209 OperationNode *op_from = (OperationNode *)rel->from;
210 if ((rel->flag & RELATION_FLAG_CYCLIC) == 0) {
211 BLI_assert(op_from->num_links_pending > 0);
212 --op_from->num_links_pending;
213 }
214 if ((op_from->num_links_pending == 0) && (op_from->custom_flags & DEG_NODE_VISITED) == 0) {
215 stack.push(op_from);
216 op_from->custom_flags |= DEG_NODE_VISITED;
217 }
218 }
219 }
220 }
221
222 graph->need_update_nodes_visibility = false;
223}
224
226{
227 if (!graph->need_update_nodes_visibility) {
228 return;
229 }
230
232}
233
234} // namespace blender::deg
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
@ DAG_EVAL_VIEWPORT
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
@ ID_OB
@ BASE_ENABLED_RENDER
@ BASE_ENABLED_VIEWPORT
@ eModifierMode_Render
@ eModifierMode_Realtime
Object is a sort of wrapper for general info.
BPy_StructRNA * depsgraph
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
#define GS(x)
void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node)
void deg_graph_flush_visibility_flags(Depsgraph *graph)
void deg_evaluate_object_modifiers_mode_node_visibility(::Depsgraph *depsgraph, IDNode *id_node)
void deg_graph_flush_visibility_flags_if_needed(Depsgraph *graph)
char name[258]
Definition DNA_ID.h:432
ListBase modifiers
OperationNode * find_operation(OperationIDKey key) const
OperationNodes operations
Definition depsgraph.hh:133
eEvaluationMode mode
Definition depsgraph.hh:143
Map< ComponentIDKey, ComponentNode * > components
ComponentNode * find_component(NodeType type, StringRef name="") const
Relations inlinks
Definition deg_node.hh:182
Relations outlinks
Definition deg_node.hh:183