fda665b0db4284933fa4051c3a20974bb0f1baf0
[blender-staging.git] / source / blender / depsgraph / intern / eval / deg_eval_flush.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  * Original Author: Joshua Leung
22  * Contributor(s): None Yet
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/depsgraph/intern/depsgraph_tag.cc
28  *  \ingroup depsgraph
29  *
30  * Core routines for how the Depsgraph works.
31  */
32
33 #include "intern/eval/deg_eval_flush.h"
34
35 // TODO(sergey): Use some sort of wrapper.
36 #include <queue>
37
38 extern "C" {
39 #include "DNA_object_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_task.h"
43 #include "BLI_ghash.h"
44
45 #include "DEG_depsgraph.h"
46 } /* extern "C" */
47
48 #include "intern/nodes/deg_node.h"
49 #include "intern/nodes/deg_node_component.h"
50 #include "intern/nodes/deg_node_operation.h"
51
52 #include "intern/depsgraph_intern.h"
53 #include "util/deg_util_foreach.h"
54
55 namespace DEG {
56
57 namespace {
58
59 // TODO(sergey): De-duplicate with depsgraph_tag,cc
60 void lib_id_recalc_tag(Main *bmain, ID *id)
61 {
62         id->tag |= LIB_TAG_ID_RECALC;
63         DEG_id_type_tag(bmain, GS(id->name));
64 }
65
66 void lib_id_recalc_data_tag(Main *bmain, ID *id)
67 {
68         id->tag |= LIB_TAG_ID_RECALC_DATA;
69         DEG_id_type_tag(bmain, GS(id->name));
70 }
71
72 }  /* namespace */
73
74 typedef std::queue<OperationDepsNode *> FlushQueue;
75
76 static void flush_init_func(void *data_v, int i)
77 {
78         /* ID node's done flag is used to avoid multiple editors update
79          * for the same ID.
80          */
81         Depsgraph *graph = (Depsgraph *)data_v;
82         OperationDepsNode *node = graph->operations[i];
83         ComponentDepsNode *comp_node = node->owner;
84         IDDepsNode *id_node = comp_node->owner;
85         id_node->done = 0;
86         comp_node->done = 0;
87         node->scheduled = false;
88         if (comp_node->type == DEPSNODE_TYPE_PROXY) {
89                 node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
90         }
91 }
92
93 /* Flush updates from tagged nodes outwards until all affected nodes
94  * are tagged.
95  */
96 void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
97 {
98         /* Sanity check. */
99         if (graph == NULL) {
100                 return;
101         }
102
103         /* Nothing to update, early out. */
104         if (BLI_gset_size(graph->entry_tags) == 0) {
105                 return;
106         }
107
108         /* TODO(sergey): With a bit of flag magic we can get rid of this
109          * extra loop.
110          */
111         const int num_operations = graph->operations.size();
112         const bool do_threads = num_operations > 256;
113         BLI_task_parallel_range(0,
114                                 num_operations,
115                                 graph,
116                                 flush_init_func,
117                                 do_threads);
118
119         FlushQueue queue;
120         /* Starting from the tagged "entry" nodes, flush outwards... */
121         /* NOTE: Also need to ensure that for each of these, there is a path back to
122          *       root, or else they won't be done.
123          * NOTE: Count how many nodes we need to handle - entry nodes may be
124          *       component nodes which don't count for this purpose!
125          */
126         GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
127         {
128                 queue.push(node);
129                 node->scheduled = true;
130         }
131         GSET_FOREACH_END();
132
133         while (!queue.empty()) {
134                 OperationDepsNode *node = queue.front();
135                 queue.pop();
136
137                 for (;;) {
138                         node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
139
140                         ComponentDepsNode *comp_node = node->owner;
141                         IDDepsNode *id_node = comp_node->owner;
142                         id_node->done = 1;
143                         comp_node->done = 1;
144
145                         /* Flush to nodes along links... */
146                         if (node->outlinks.size() == 1) {
147                                 OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
148                                 if (to_node->scheduled == false) {
149                                         to_node->scheduled = true;
150                                         node = to_node;
151                                 }
152                                 else {
153                                         break;
154                                 }
155                         }
156                         else {
157                                 foreach (DepsRelation *rel, node->outlinks) {
158                                         OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
159                                         if (to_node->scheduled == false) {
160                                                 queue.push(to_node);
161                                                 to_node->scheduled = true;
162                                         }
163                                 }
164                                 break;
165                         }
166                 }
167         }
168
169         GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
170         {
171                 if (id_node->done == 1) {
172                         ID *id = id_node->id;
173                         Object *object = NULL;
174
175                         if (GS(id->name) == ID_OB) {
176                                 object = (Object *)id;
177                         }
178
179                         deg_editors_id_update(bmain, id_node->id);
180
181                         lib_id_recalc_tag(bmain, id_node->id);
182                         /* TODO(sergey): For until we've got proper data nodes in the graph. */
183                         lib_id_recalc_data_tag(bmain, id_node->id);
184
185                         GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components)
186                         {
187                                 if (comp_node->done) {
188                                         foreach (OperationDepsNode *op, comp_node->operations) {
189                                                 op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
190                                         }
191                                         if (object != NULL) {
192                                                 /* This code is used to preserve those areas which does
193                                                  * direct object update,
194                                                  *
195                                                  * Plus it ensures visibility changes and relations and
196                                                  * layers visibility update has proper flags to work with.
197                                                  */
198                                                 if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
199                                                         object->recalc |= OB_RECALC_TIME;
200                                                 }
201                                                 else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
202                                                         object->recalc |= OB_RECALC_OB;
203                                                 }
204                                                 else {
205                                                         object->recalc |= OB_RECALC_DATA;
206                                                 }
207                                         }
208                                 }
209                         }
210                         GHASH_FOREACH_END();
211                 }
212         }
213         GHASH_FOREACH_END();
214 }
215
216 static void graph_clear_func(void *data_v, int i)
217 {
218         Depsgraph *graph = (Depsgraph *)data_v;
219         OperationDepsNode *node = graph->operations[i];
220         /* Clear node's "pending update" settings. */
221         node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
222 }
223
224 /* Clear tags from all operation nodes. */
225 void deg_graph_clear_tags(Depsgraph *graph)
226 {
227         /* Go over all operation nodes, clearing tags. */
228         const int num_operations = graph->operations.size();
229         const bool do_threads = num_operations > 256;
230         BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
231         /* Clear any entry tags which haven't been flushed. */
232         BLI_gset_clear(graph->entry_tags, NULL);
233 }
234
235 }  // namespace DEG