Blender V4.3
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
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.h"
18
19#include "DEG_depsgraph.hh"
20
21#include "intern/depsgraph.hh"
27
28namespace blender::deg {
29
31{
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{
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);
71 LISTBASE_FOREACH (ModifierData *, modifier, &object->modifiers) {
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
125 BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack");
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 BLI_stack_push(stack, &op_node);
137 op_node->custom_flags |= DEG_NODE_VISITED;
138 }
139 }
140
141 while (!BLI_stack_is_empty(stack)) {
142 OperationNode *op_node;
143 BLI_stack_pop(stack, &op_node);
144
145 /* Flush flags to parents. */
146 for (Relation *rel : op_node->inlinks) {
147 if (rel->from->type == NodeType::OPERATION) {
148 const OperationNode *op_to = reinterpret_cast<const OperationNode *>(rel->to);
149 const ComponentNode *comp_to = op_to->owner;
150
151 /* Ignore the synchronization target.
152 * It is always visible and should not affect on other components. */
153 if (comp_to->type == NodeType::SYNCHRONIZATION) {
154 continue;
155 }
156
157 OperationNode *op_from = reinterpret_cast<OperationNode *>(rel->from);
158 ComponentNode *comp_from = op_from->owner;
159
161
162 if (rel->flag & RELATION_NO_VISIBILITY_CHANGE) {
163 continue;
164 }
165
166 const bool target_possibly_affects_visible_id = comp_to->possibly_affects_visible_id;
167
168 bool target_affects_visible_id = comp_to->affects_visible_id;
169
170 /* This is a bit arbitrary but the idea here is following:
171 *
172 * - When another object is used by a disabled modifier we do not want that object to
173 * be considered needed for evaluation.
174 *
175 * - However, we do not want to take mute flag during visibility propagation within the
176 * same object. Otherwise drivers and transform dependencies of the geometry component
177 * entry component might not be properly handled.
178 *
179 * This code works fine for muting modifiers, but might need tweaks when mute is used for
180 * something else. */
181 if (comp_from != comp_to && (op_to->flag & DEPSOP_FLAG_MUTE)) {
182 target_affects_visible_id = false;
183 }
184
185 /* Visibility component forces all components of the current ID to be considered as
186 * affecting directly visible. */
187 if (comp_from->type == NodeType::VISIBILITY) {
188 const IDNode *id_node_from = comp_from->owner;
189 if (target_possibly_affects_visible_id) {
190 for (ComponentNode *comp_node : id_node_from->components.values()) {
191 comp_node->possibly_affects_visible_id |= target_possibly_affects_visible_id;
192 }
193 }
194 if (target_affects_visible_id) {
195 for (ComponentNode *comp_node : id_node_from->components.values()) {
196 comp_node->affects_visible_id |= target_affects_visible_id;
197 }
198 }
199 }
200 else {
201 comp_from->possibly_affects_visible_id |= target_possibly_affects_visible_id;
202 comp_from->affects_visible_id |= target_affects_visible_id;
203 }
204 }
205 }
206
207 /* Schedule parent nodes. */
208 for (Relation *rel : op_node->inlinks) {
209 if (rel->from->type == NodeType::OPERATION) {
210 OperationNode *op_from = (OperationNode *)rel->from;
211 if ((rel->flag & RELATION_FLAG_CYCLIC) == 0) {
212 BLI_assert(op_from->num_links_pending > 0);
213 --op_from->num_links_pending;
214 }
215 if ((op_from->num_links_pending == 0) && (op_from->custom_flags & DEG_NODE_VISITED) == 0) {
216 BLI_stack_push(stack, &op_from);
217 op_from->custom_flags |= DEG_NODE_VISITED;
218 }
219 }
220 }
221 }
222 BLI_stack_free(stack);
223
224 graph->need_update_nodes_visibility = false;
225}
226
228{
229 if (!graph->need_update_nodes_visibility) {
230 return;
231 }
232
234}
235
236} // namespace blender::deg
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition stack.c:137
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.c:131
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:249
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:96
#define BLI_stack_new(esize, descr)
@ 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.
const IDNode * id_node
const Depsgraph * depsgraph
#define GS(x)
Definition iris.cc:202
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[66]
Definition DNA_ID.h:425
OperationNode * find_operation(OperationIDKey key) const
Map< ComponentIDKey, ComponentNode * > components
ComponentNode * find_component(NodeType type, const char *name="") const
Relations inlinks
Definition deg_node.hh:180