Blender V5.0
depsgraph.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "intern/depsgraph.hh" /* own include */
12
13#include <cstring>
14#include <type_traits>
15
16#include "BLI_utildefines.h"
17
18#include "BKE_global.hh"
19#include "BKE_idtype.hh"
20#include "BKE_scene.hh"
21
22#include "DEG_depsgraph.hh"
24
28
30
37
38namespace deg = blender::deg;
39
40namespace blender::deg {
41
72
79
80/* Node Management ---------------------------- */
81
83{
84 if (time_source == nullptr) {
86 time_source = (TimeSourceNode *)factory->create_node(nullptr, "", "Time Source");
87 }
88 return time_source;
89}
90
95
100
102{
103 return id_hash.lookup_default(id, nullptr);
104}
105
107{
109 IDNode *id_node = find_id_node(id);
110 if (!id_node) {
112 id_node = (IDNode *)factory->create_node(id, "", id->name);
113 id_node->init_copy_on_write(id_cow_hint);
114 /* Register node in ID hash.
115 *
116 * NOTE: We address ID nodes by the original ID pointer they are
117 * referencing to. */
118 id_hash.add_new(id, id_node);
119 id_nodes.append(id_node);
120
122 }
123 return id_node;
124}
125
126template<typename FilterFunc>
127static void clear_id_nodes_conditional(Depsgraph::IDDepsNodes *id_nodes, const FilterFunc &filter)
128{
129 for (IDNode *id_node : *id_nodes) {
130 if (id_node->id_cow == nullptr) {
131 /* This means builder "stole" ownership of the evaluated
132 * datablock for its own dirty needs. */
133 continue;
134 }
135 if (id_node->id_cow == id_node->id_orig) {
136 /* Evaluated copy is not needed for this ID type.
137 *
138 * NOTE: Is important to not de-reference the original datablock here because it might be
139 * freed already (happens during main database free when some IDs are freed prior to a
140 * scene). */
141 continue;
142 }
143 if (!deg_eval_copy_is_expanded(id_node->id_cow)) {
144 continue;
145 }
146 const ID_Type id_type = GS(id_node->id_cow->name);
147 if (filter(id_type)) {
148 id_node->destroy();
149 }
150 }
151}
152
154{
155 /* Free memory used by ID nodes. */
156
157 /* Stupid workaround to ensure we free IDs in a proper order. */
158 clear_id_nodes_conditional(&id_nodes, [](ID_Type id_type) { return id_type == ID_SCE; });
159 clear_id_nodes_conditional(&id_nodes, [](ID_Type id_type) { return id_type != ID_PA; });
160
161 for (IDNode *id_node : id_nodes) {
162 delete id_node;
163 }
164 /* Clear containers. */
165 id_hash.clear();
166 id_nodes.clear();
167 /* Clear physics relation caches. */
169
170 light_linking_cache.clear();
171}
172
173Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags)
174{
175 Relation *rel = nullptr;
176 if (flags & RELATION_CHECK_BEFORE_ADD) {
177 rel = check_nodes_connected(from, to, description);
178 }
179 if (rel != nullptr) {
180 rel->flag |= flags;
181 return rel;
182 }
183
184#ifndef NDEBUG
185 if (from->type == NodeType::OPERATION && to->type == NodeType::OPERATION) {
186 OperationNode *operation_from = static_cast<OperationNode *>(from);
187 OperationNode *operation_to = static_cast<OperationNode *>(to);
188 BLI_assert(operation_to->owner->type != NodeType::COPY_ON_EVAL ||
189 operation_from->owner->type == NodeType::COPY_ON_EVAL);
190 }
191#endif
192
193 /* Create new relation, and add it to the graph. The type must be trivially destructible for
194 * `.release()` to be okay. If it weren't, we could store the relations with #destruct_ptr on
195 * either the `inlinks` or `outlinks`. But since so many #Relation structs are allocated, it's
196 * probably better for it be a simple type anyway. */
197 static_assert(std::is_trivially_destructible_v<Relation>);
198 rel = this->build_allocator.construct<Relation>(from, to, description).release();
199 from->outlinks.append(rel);
200 to->inlinks.append(rel);
201 rel->flag |= flags;
202 return rel;
203}
204
206 const Node *to,
207 const char *description)
208{
209 for (Relation *rel : from->outlinks) {
210 BLI_assert(rel->from == from);
211 if (rel->to != to) {
212 continue;
213 }
214 if (description != nullptr && !STREQ(rel->name, description)) {
215 continue;
216 }
217 return rel;
218 }
219 return nullptr;
220}
221
222/* Low level tagging -------------------------------------- */
223
225{
226 /* Sanity check. */
227 if (node == nullptr) {
228 return;
229 }
230 /* Add to graph-level set of directly modified nodes to start searching
231 * from.
232 * NOTE: this is necessary since we have several thousand nodes to play
233 * with. */
234 entry_tags.add(node);
235}
236
238{
240 delete time_source;
241 time_source = nullptr;
242 /* Memory used by the build allocator is now unused. Rebuild it from scratch. */
243 std::destroy_at(&this->build_allocator);
244 new (&this->build_allocator) LinearAllocator<>();
245}
246
247ID *Depsgraph::get_cow_id(const ID *id_orig) const
248{
249 IDNode *id_node = find_id_node(id_orig);
250 if (id_node == nullptr) {
251 /* This function is used from places where we expect ID to be either
252 * already a copy-on-evaluation version or have a corresponding copy-on-evaluation
253 * version.
254 *
255 * We try to enforce that in debug builds, for release we play a bit
256 * safer game here. */
257 if ((id_orig->tag & ID_TAG_COPIED_ON_EVAL) == 0) {
258 /* TODO(sergey): This is nice sanity check to have, but it fails
259 * in following situations:
260 *
261 * - Material has link to texture, which is not needed by new
262 * shading system and hence can be ignored at construction.
263 * - Object or mesh has material at a slot which is not used (for
264 * example, object has material slot by materials are set to
265 * object data). */
266 // BLI_assert_msg(0, "Request for non-existing copy-on-evaluation ID");
267 }
268 return (ID *)id_orig;
269 }
270 return id_node->id_cow;
271}
272
273} // namespace blender::deg
274
275/* **************** */
276/* Public Graph API */
277
278Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
279{
280 deg::Depsgraph *deg_depsgraph = new deg::Depsgraph(bmain, scene, view_layer, mode);
281 deg::register_graph(deg_depsgraph);
282 return reinterpret_cast<Depsgraph *>(deg_depsgraph);
283}
284
286 Main *bmain,
287 Scene *scene,
288 ViewLayer *view_layer)
289{
290 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
291
292 const bool do_update_register = deg_graph->bmain != bmain;
293 if (do_update_register && deg_graph->bmain != nullptr) {
294 deg::unregister_graph(deg_graph);
295 }
296
297 deg_graph->bmain = bmain;
298 deg_graph->scene = scene;
299 deg_graph->view_layer = view_layer;
300
301 if (do_update_register) {
302 deg::register_graph(deg_graph);
303 }
304}
305
306void DEG_graph_free(Depsgraph *graph)
307{
308 if (graph == nullptr) {
309 return;
310 }
311 using deg::Depsgraph;
312 deg::Depsgraph *deg_depsgraph = reinterpret_cast<deg::Depsgraph *>(graph);
313 deg::unregister_graph(deg_depsgraph);
314 delete deg_depsgraph;
315}
316
317bool DEG_is_evaluating(const Depsgraph *depsgraph)
318{
319 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
320 return deg_graph->is_evaluating;
321}
322
323bool DEG_is_active(const Depsgraph *depsgraph)
324{
325 if (depsgraph == nullptr) {
326 /* Happens for such cases as work object in what_does_obaction(),
327 * and sine render pipeline parts. Shouldn't really be accepting
328 * nullptr depsgraph, but is quite hard to get proper one in those
329 * cases. */
330 return false;
331 }
332 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
333 return deg_graph->is_active;
334}
335
337{
338 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
339 deg_graph->is_active = true;
340 /* TODO(sergey): Copy data from evaluated state to original. */
341}
342
344{
345 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
346 deg_graph->is_active = false;
347}
348
350{
351 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
352 deg_graph->use_visibility_optimization = false;
353}
354
356{
357 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
358 return deg_graph->update_count;
359}
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:228
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#define STREQ(a, b)
bool DEG_is_evaluating(const Depsgraph *depsgraph)
Definition depsgraph.cc:317
@ DEG_EVALUATE_SYNC_WRITEBACK_NO
uint64_t DEG_get_update_count(const Depsgraph *depsgraph)
Definition depsgraph.cc:355
void DEG_disable_visibility_optimization(Depsgraph *depsgraph)
Definition depsgraph.cc:349
eEvaluationMode
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:278
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
void DEG_graph_replace_owners(Depsgraph *depsgraph, Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition depsgraph.cc:285
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
void DEG_make_inactive(Depsgraph *depsgraph)
Definition depsgraph.cc:343
void DEG_make_active(Depsgraph *depsgraph)
Definition depsgraph.cc:336
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:997
ID_Type
@ ID_SCE
@ ID_PA
return true
BPy_StructRNA * depsgraph
unsigned long long int uint64_t
void append(const T &value)
#define GS(x)
#define filter
bool deg_eval_copy_is_expanded(const ID *id_cow)
static void clear_id_nodes_conditional(Depsgraph::IDDepsNodes *id_nodes, const FilterFunc &filter)
Definition depsgraph.cc:127
void clear_physics_relations(Depsgraph *graph)
DepsNodeFactory * type_get_factory(const NodeType type)
void unregister_graph(Depsgraph *depsgraph)
void register_graph(Depsgraph *depsgraph)
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
virtual Node * create_node(const ID *id, const char *subdata, StringRef name) const =0
ID * get_cow_id(const ID *id_orig) const
Definition depsgraph.cc:247
Map< const ID *, ListBase * > * physics_relations[DEG_PHYSICS_RELATIONS_NUM]
Definition depsgraph.hh:181
IDNode * find_id_node(const ID *id) const
Definition depsgraph.cc:101
char id_type_updated[INDEX_ID_MAX]
Definition depsgraph.hh:117
bool need_tag_id_on_graph_visibility_time_update
Definition depsgraph.hh:114
LinearAllocator build_allocator
Definition depsgraph.hh:88
light_linking::Cache light_linking_cache
Definition depsgraph.hh:183
bool need_tag_id_on_graph_visibility_update
Definition depsgraph.hh:113
TimeSourceNode * find_time_source() const
Definition depsgraph.cc:91
IDNode * add_id_node(ID *id, ID *id_cow_hint=nullptr)
Definition depsgraph.cc:106
Vector< IDNode * > IDDepsNodes
Definition depsgraph.hh:50
eEvaluationMode mode
Definition depsgraph.hh:143
char id_type_updated_backup[INDEX_ID_MAX]
Definition depsgraph.hh:119
Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:42
DepsgraphEvaluateSyncWriteback sync_writeback
Definition depsgraph.hh:189
Relation * add_new_relation(Node *from, Node *to, const char *description, int flags=0)
Definition depsgraph.cc:173
char id_type_exist[INDEX_ID_MAX]
Definition depsgraph.hh:122
Map< const ID *, IDNode * > id_hash
Definition depsgraph.hh:92
Relation * check_nodes_connected(const Node *from, const Node *to, const char *description)
Definition depsgraph.cc:205
TimeSourceNode * add_time_source()
Definition depsgraph.cc:82
Set< OperationNode * > entry_tags
Definition depsgraph.hh:127
TimeSourceNode * time_source
Definition depsgraph.hh:100
void add_entry_tag(OperationNode *node)
Definition depsgraph.cc:224
void init_copy_on_write(ID *id_cow_hint=nullptr)
Relations inlinks
Definition deg_node.hh:182
Relations outlinks
Definition deg_node.hh:183