Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/depsgraph/intern')
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc33
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc19
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc148
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h49
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.cc94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.h140
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc69
12 files changed, 497 insertions, 79 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 8ee94ab0a34..a3cd821e82f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -54,9 +54,9 @@ bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base)
return id_node->has_base;
}
-/*******************************************************************************
- * Base class for builders.
- */
+/* -------------------------------------------------------------------- */
+/** \name Base Class for Builders
+ * \{ */
DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache)
: bmain_(bmain), graph_(graph), cache_(cache)
@@ -120,9 +120,11 @@ bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const char
return check_pchan_has_bbone_segments(object, pchan);
}
-/*******************************************************************************
- * Builder finalizer.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Builder Finalizer.
+ * \{ */
namespace {
@@ -136,8 +138,22 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
for (IDNode *id_node : graph->id_nodes) {
for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->affects_directly_visible |= id_node->is_directly_visible;
+
+ /* Enforce "visibility" of the synchronization component.
+ *
+ * This component is never connected to other ID nodes, and hence can not be handled in the
+ * same way as other components needed for evaluation. It is only needed for proper
+ * evaluation of the ID node it belongs to.
+ *
+ * The design is such that the synchronization is supposed to happen whenever any part of the
+ * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag
+ * flushing and scheduling will handle the component in a generic manner. */
+ if (comp_node->type == NodeType::SYNCHRONIZATION) {
+ comp_node->affects_directly_visible = true;
+ }
}
}
+
for (OperationNode *op_node : graph->operations) {
op_node->custom_flags = 0;
op_node->num_links_pending = 0;
@@ -151,6 +167,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
op_node->custom_flags |= DEG_NODE_VISITED;
}
}
+
while (!BLI_stack_is_empty(stack)) {
OperationNode *op_node;
BLI_stack_pop(stack, &op_node);
@@ -198,7 +215,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
{
- /* Make sure dependencies of visible ID datablocks are visible. */
+ /* Make sure dependencies of visible ID data-blocks are visible. */
deg_graph_build_flush_visibility(graph);
deg_graph_remove_unused_noops(graph);
@@ -233,4 +250,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
}
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d632c4e2f7e..8ba6c840a59 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -42,9 +42,7 @@ struct StackEntry {
struct CyclesSolverState {
CyclesSolverState(Depsgraph *graph)
- : graph(graph),
- traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")),
- num_cycles(0)
+ : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack"))
{
/* pass */
}
@@ -57,7 +55,7 @@ struct CyclesSolverState {
}
Depsgraph *graph;
BLI_Stack *traversal_stack;
- int num_cycles;
+ int num_cycles = 0;
};
inline void set_node_visited_state(Node *node, eCyclicCheckVisitedState state)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 4782f1c4a5d..657bc3eb25c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -78,6 +78,7 @@
#include "BKE_modifier.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -1078,14 +1079,18 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
- /* GPU materials might use an animated image. However, these materials have no been built yet. We
- * could scan the entire node tree recursively to check if any texture node has a video. That is
- * quite expensive. For now just always add this operation node, because it is very fast. */
- /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node
- * tree. */
- const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+ /* GPU materials might use an animated image. However, these materials have no been built yet so
+ * we have to check if they might be created during evaluation. */
+ bool has_image_animation = false;
+ if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+ bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ has_image_animation = true;
+ }
+ }
- if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+ if (has_image_animation || BKE_image_user_id_has_animation(id)) {
ID *id_cow = get_cow_id(id);
add_operation_node(
id,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 23147b63e27..c13c6d2f870 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -71,6 +71,7 @@
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -586,11 +587,12 @@ void DepsgraphRelationBuilder::build_id(ID *id)
void DepsgraphRelationBuilder::build_generic_id(ID *id)
{
-
if (built_map_.checkIsBuiltAndTag(id)) {
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+
build_idproperties(id->properties);
build_animdata(id);
build_parameters(id);
@@ -621,6 +623,9 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
* recurses into all the nested objects and collections. */
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(collection->id);
+
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
NodeType::TRANSFORM,
@@ -684,6 +689,9 @@ void DepsgraphRelationBuilder::build_object(Object *object)
if (built_map_.checkIsBuiltAndTag(object)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(object->id);
+
/* Object Transforms */
OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT :
OperationCode::TRANSFORM_LOCAL;
@@ -1129,10 +1137,14 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
/* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {nullptr, nullptr};
/* Invalid constraint type. */
if (cti == nullptr) {
continue;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
/* Special case for camera tracking -- it doesn't use targets to
* define relations. */
/* TODO: we can now represent dependencies in a much richer manner,
@@ -1177,9 +1189,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(cache_key, constraint_op_key, cti->name);
}
}
- else if (cti->get_constraint_targets) {
- ListBase targets = {nullptr, nullptr};
- cti->get_constraint_targets(con, &targets);
+ else if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == nullptr) {
continue;
@@ -1289,9 +1299,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
}
}
@@ -1446,10 +1454,16 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
void DepsgraphRelationBuilder::build_animation_images(ID *id)
{
/* See #DepsgraphNodeBuilder::build_animation_images. */
- const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+ bool has_image_animation = false;
+ if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+ bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ has_image_animation = true;
+ }
+ }
- /* TODO: can we check for existence of node for performance? */
- if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+ if (has_image_animation || BKE_image_user_id_has_animation(id)) {
OperationKey image_animation_key(
id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
TimeSourceKey time_src_key;
@@ -1495,6 +1509,9 @@ void DepsgraphRelationBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(action->id);
+
build_idproperties(action->id.properties);
if (!BLI_listbase_is_empty(&action->curves)) {
TimeSourceKey time_src_key;
@@ -1693,6 +1710,53 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
continue;
}
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
+
+ /* It is possible that RNA path points to a property of a different ID than the target_id:
+ * for example, paths like "data" on Object, "camera" on Scene.
+ *
+ * For the demonstration purposes lets consider a driver variable uses Scene ID as target
+ * and "camera.location.x" as its RNA path. If the scene has 2 different cameras at
+ * 2 different locations changing the active scene camera is expected to immediately be
+ * reflected in the variable value. In order to achieve this behavior we create a relation
+ * from the target ID to the driver so that if the ID property of the target ID changes the
+ * driver is re-evaluated.
+ *
+ * The most straightforward (at the moment of writing this comment) way of figuring out
+ * such relation is to use copy-on-write operation of the target ID. There are two down
+ * sides of this approach which are considered a design limitation as there is a belief
+ * that they are not common in practice or are not reliable due to other issues:
+ *
+ * - IDs which are not covered with the copy-on-write mechanism.
+ *
+ * Such IDs are either do not have ID properties, or are not part of the dependency
+ * graph.
+ *
+ * - Modifications of evaluated IDs from a Python handler.
+ * Such modifications are not fully integrated in the dependency graph evaluation as it
+ * has issues with copy-on-write tagging and the fact that relations are defined by the
+ * original main database status. */
+ if (target_id != variable_exit_key.ptr.owner_id) {
+ if (deg_copy_on_write_is_needed(GS(target_id->name))) {
+ ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE);
+ add_relation(target_id_key, driver_key, "Target ID -> Driver");
+ }
+ }
+
+ /* The RNA getter for `object.data` can write to the mesh datablock due
+ * to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
+ * ensures it is safe to call when the driver is evaluated.
+ *
+ * For the sake of making the code more generic/defensive, the relation
+ * is added for any geometry type.
+ *
+ * See T96289 for more info. */
+ if (object != nullptr && OB_TYPE_IS_GEOMETRY(object->type)) {
+ StringRef rna_path(dtar->rna_path);
+ if (rna_path == "data" || rna_path.startswith("data.")) {
+ ComponentKey ob_key(target_id, NodeType::GEOMETRY);
+ add_relation(ob_key, driver_key, "ID -> Driver");
+ }
+ }
}
else {
/* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
@@ -1766,6 +1830,9 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(world->id);
+
build_idproperties(world->id.properties);
/* animation */
build_animdata(&world->id);
@@ -1991,6 +2058,9 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
if (built_map_.checkIsBuiltAndTag(part)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(part->id);
+
/* Animation data relations. */
build_animdata(&part->id);
build_parameters(&part->id);
@@ -2049,6 +2119,9 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(key->id);
+
build_idproperties(key->id.properties);
/* Attach animdata to geometry. */
build_animdata(&key->id);
@@ -2110,6 +2183,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->updateDepsgraph) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*md);
+
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
@@ -2230,6 +2305,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*obdata);
+
build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
@@ -2348,6 +2426,9 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(armature->id);
+
build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
@@ -2367,6 +2448,9 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(camera->id);
+
build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
@@ -2384,6 +2468,9 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(lamp->id);
+
build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
@@ -2448,6 +2535,9 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(ntree->id);
+
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
@@ -2553,6 +2643,9 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(material->id);
+
build_idproperties(material->id.properties);
/* animation */
build_animdata(&material->id);
@@ -2589,6 +2682,9 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
if (built_map_.checkIsBuiltAndTag(texture)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(texture->id);
+
/* texture itself */
ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
build_idproperties(texture->id.properties);
@@ -2630,6 +2726,9 @@ void DepsgraphRelationBuilder::build_image(Image *image)
if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(image->id);
+
build_idproperties(image->id.properties);
build_parameters(&image->id);
}
@@ -2639,6 +2738,9 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
if (built_map_.checkIsBuiltAndTag(cache_file)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(cache_file->id);
+
build_idproperties(cache_file->id.properties);
/* Animation. */
build_animdata(&cache_file->id);
@@ -2668,6 +2770,9 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
if (built_map_.checkIsBuiltAndTag(mask)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(mask->id);
+
ID *mask_id = &mask->id;
build_idproperties(mask_id->properties);
/* F-Curve animation. */
@@ -2706,6 +2811,8 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(linestyle->id);
+
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
build_idproperties(linestyle_id->properties);
@@ -2718,6 +2825,9 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
if (built_map_.checkIsBuiltAndTag(clip)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(clip->id);
+
/* Animation. */
build_idproperties(clip->id.properties);
build_animdata(&clip->id);
@@ -2729,6 +2839,9 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(probe->id);
+
build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
@@ -2739,6 +2852,9 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
if (built_map_.checkIsBuiltAndTag(speaker)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(speaker->id);
+
build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
@@ -2755,6 +2871,9 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(sound->id);
+
build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
@@ -2765,6 +2884,9 @@ void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
if (built_map_.checkIsBuiltAndTag(simulation)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(simulation->id);
+
build_idproperties(simulation->id.properties);
build_animdata(&simulation->id);
build_parameters(&simulation->id);
@@ -2829,6 +2951,9 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_SEQUENCER)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene sequencer. */
+
build_scene_audio(scene);
ComponentKey scene_audio_key(&scene->id, NodeType::AUDIO);
/* Make sure dependencies from sequences data goes to the sequencer evaluation. */
@@ -2872,6 +2997,9 @@ void DepsgraphRelationBuilder::build_vfont(VFont *vfont)
if (built_map_.checkIsBuiltAndTag(vfont)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(vfont->id);
+
build_parameters(&vfont->id);
build_idproperties(vfont->id.properties);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 1ccecc9a3f2..64bdd2334d8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -23,6 +23,7 @@
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_map.h"
#include "intern/builder/deg_builder_rna.h"
+#include "intern/builder/deg_builder_stack.h"
#include "intern/depsgraph.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
@@ -363,6 +364,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
BuilderMap built_map_;
RNANodeQuery rna_node_query_;
+ BuilderStack stack_;
};
struct DepsNodeHandle {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index 5cbd8c8dd75..aba4a011e72 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -9,6 +9,8 @@
#include "intern/node/deg_node_id.h"
+#include <iostream>
+
#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
@@ -33,37 +35,30 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
Node *node_to = get_node(key_to);
OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr;
OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr;
+
if (op_from && op_to) {
return add_operation_relation(op_from, op_to, description, flags);
}
- else {
- if (!op_from) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_from (%s)\n",
- description,
- key_from.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_from (%s) was ok\n",
- description,
- key_from.identifier().c_str());
- }
- if (!op_to) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_to (%s)\n",
- description,
- key_to.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_to (%s) was ok\n",
- description,
- key_to.identifier().c_str());
- }
+
+ /* TODO(sergey): Report error in the interface. */
+
+ std::cerr << "--------------------------------------------------------------------\n";
+ std::cerr << "Failed to add relation \"" << description << "\"\n";
+
+ if (!op_from) {
+ std::cerr << "Could not find op_from: " << key_from.identifier() << "\n";
+ }
+
+ if (!op_to) {
+ std::cerr << "Could not find op_to: " << key_to.identifier() << "\n";
}
+
+ if (!stack_.is_empty()) {
+ std::cerr << "\nTrace:\n\n";
+ stack_.print_backtrace(std::cerr);
+ std::cerr << "\n";
+ }
+
return nullptr;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 65cf0e7d9df..2e491cd37a6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -322,7 +322,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(object, pchan, con, &root_map);
@@ -356,6 +360,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index cdb7361afc0..cd1917cb607 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -36,6 +36,9 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene parameters. */
+
build_idproperties(scene->id.properties);
build_parameters(&scene->id);
OperationKey parameters_eval_key(
@@ -56,6 +59,9 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene)
if (scene->nodetree == nullptr) {
return;
}
+
+ /* TODO(sergey): Trace as a scene compositor. */
+
build_nodetree(scene->nodetree);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 8a81adf0aeb..ac7a5bc2f30 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -39,7 +39,7 @@ namespace blender::deg {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id)
{
}
@@ -77,7 +77,7 @@ class RNANodeQueryIDData {
/* indexed by bConstraint*, returns pose channel which contains that
* constraint. */
- Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_;
+ Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_ = nullptr;
};
/* ***************************** Node Identifier **************************** */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.cc b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
new file mode 100644
index 00000000000..de0a5198a8a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder_stack.h"
+
+#include <iomanip>
+#include <ios>
+#include <iostream>
+
+#include "BKE_idtype.h"
+
+#include "DNA_ID.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+
+namespace blender::deg {
+
+/* Spacing between adjacent columns, in number of spaces. */
+constexpr int kColumnSpacing = 4;
+
+/* Width of table columns including column padding.
+ * The type column width is a guesstimate based on "Particle Settings" with some extra padding. */
+constexpr int kPrintDepthWidth = 5 + kColumnSpacing;
+constexpr int kPrintTypeWidth = 21 + kColumnSpacing;
+
+namespace {
+
+/* NOTE: Depth column printing is already taken care of. */
+
+void print(std::ostream &stream, const ID *id)
+{
+ const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
+ stream << std::setw(kPrintTypeWidth) << id_type_info->name << (id->name + 2) << "\n";
+}
+
+void print(std::ostream &stream, const bConstraint *constraint)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Constraint") << constraint->name << "\n";
+}
+
+void print(std::ostream &stream, const ModifierData *modifier_data)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Modifier") << modifier_data->name << "\n";
+}
+
+void print(std::ostream &stream, const bPoseChannel *pchan)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Pose Channel") << pchan->name << "\n";
+}
+
+} // namespace
+
+void BuilderStack::print_backtrace(std::ostream &stream)
+{
+ const std::ios_base::fmtflags old_flags(stream.flags());
+
+ stream << std::left;
+
+ stream << std::setw(kPrintDepthWidth) << "Depth" << std::setw(kPrintTypeWidth) << "Type"
+ << "Name"
+ << "\n";
+
+ stream << std::setw(kPrintDepthWidth) << "-----" << std::setw(kPrintTypeWidth) << "----"
+ << "----"
+ << "\n";
+
+ int depth = 1;
+ for (const Entry &entry : stack_) {
+ stream << std::setw(kPrintDepthWidth) << depth;
+ ++depth;
+
+ if (entry.id_ != nullptr) {
+ print(stream, entry.id_);
+ }
+ else if (entry.constraint_ != nullptr) {
+ print(stream, entry.constraint_);
+ }
+ else if (entry.modifier_data_ != nullptr) {
+ print(stream, entry.modifier_data_);
+ }
+ else if (entry.pchan_ != nullptr) {
+ print(stream, entry.pchan_);
+ }
+ }
+
+ stream.flags(old_flags);
+}
+
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.h b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
new file mode 100644
index 00000000000..3f9cc83928a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
+
+struct ID;
+struct bConstraint;
+struct bPoseChannel;
+struct ModifierData;
+
+namespace blender::deg {
+
+/* This class keeps track of the builder calls nesting, allowing to unroll them back and provide a
+ * clue about how the builder made it to its current state.
+ *
+ * The tracing is based on the builder giving a trace clues to the stack. Typical usage is:
+ *
+ * void DepsgraphRelationBuilder::my_id_builder(ID *id)
+ * {
+ * if (built_map_.checkIsBuiltAndTag(id)) {
+ * return;
+ * }
+ *
+ * const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+ *
+ * ...
+ * }
+ */
+class BuilderStack {
+ public:
+ /* Entry of the backtrace.
+ * A cheap-to-construct wrapper which allows to gather a proper string representation whenever
+ * the stack is printed. */
+ class Entry {
+ public:
+ explicit Entry(const ID &id) : id_(&id)
+ {
+ }
+
+ explicit Entry(const bConstraint &constraint) : constraint_(&constraint)
+ {
+ }
+
+ explicit Entry(const bPoseChannel &pchan) : pchan_(&pchan)
+ {
+ }
+
+ explicit Entry(const ModifierData &modifier_data) : modifier_data_(&modifier_data)
+ {
+ }
+
+ private:
+ friend class BuilderStack;
+
+ const ID *id_ = nullptr;
+ const bConstraint *constraint_ = nullptr;
+ const ModifierData *modifier_data_ = nullptr;
+ const bPoseChannel *pchan_ = nullptr;
+ };
+
+ using Stack = Vector<Entry>;
+
+ /* A helper class to provide a RAII style of tracing. It is constructed by the
+ * `BuilderStack::trace` (which pushes entry to the stack), and upon destruction of this object
+ * the corresponding entry is popped from the stack.
+ *
+ * The goal of this `ScopedEntry` is to free developers from worrying about removing entries from
+ * the stack whenever leaving a builder step scope. */
+ class ScopedEntry {
+ public:
+ /* Delete copy constructor and operator: scoped entries are only supposed to be constructed
+ * once and never copied. */
+ ScopedEntry(const ScopedEntry &other) = delete;
+ ScopedEntry &operator=(const ScopedEntry &other) = delete;
+
+ /* Move semantic. */
+ ScopedEntry(ScopedEntry &&other) noexcept : stack_(other.stack_)
+ {
+ other.stack_ = nullptr;
+ }
+ ScopedEntry &operator=(ScopedEntry &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ stack_ = other.stack_;
+ other.stack_ = nullptr;
+
+ return *this;
+ }
+
+ ~ScopedEntry()
+ {
+ /* Stack will become nullptr when the entry was moved somewhere else. */
+ if (stack_ != nullptr) {
+ BLI_assert(!stack_->is_empty());
+ stack_->pop_last();
+ }
+ }
+
+ private:
+ friend BuilderStack;
+
+ explicit ScopedEntry(Stack &stack) : stack_(&stack)
+ {
+ }
+
+ Stack *stack_;
+ };
+
+ BuilderStack() = default;
+ ~BuilderStack() = default;
+
+ bool is_empty() const
+ {
+ return stack_.is_empty();
+ }
+
+ void print_backtrace(std::ostream &stream);
+
+ template<class... Args> ScopedEntry trace(const Args &...args)
+ {
+ stack_.append_as(args...);
+
+ return ScopedEntry(stack_);
+ }
+
+ private:
+ Stack stack_;
+};
+
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index fd569599b8b..6ffc711a475 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -32,6 +32,49 @@
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node_id.h"
+namespace blender::deg {
+
+static const ID *get_original_id(const ID *id)
+{
+ if (id == nullptr) {
+ return nullptr;
+ }
+ if (id->orig_id == nullptr) {
+ return id;
+ }
+ BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ return (ID *)id->orig_id;
+}
+
+static ID *get_original_id(ID *id)
+{
+ const ID *const_id = id;
+ return const_cast<ID *>(get_original_id(const_id));
+}
+
+static const ID *get_evaluated_id(const Depsgraph *deg_graph, const ID *id)
+{
+ if (id == nullptr) {
+ return nullptr;
+ }
+ /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
+ * but here we never do assert, since we don't know nature of the
+ * incoming ID data-block. */
+ const IDNode *id_node = deg_graph->find_id_node(id);
+ if (id_node == nullptr) {
+ return id;
+ }
+ return id_node->id_cow;
+}
+
+static ID *get_evaluated_id(const Depsgraph *deg_graph, ID *id)
+{
+ const ID *const_id = id;
+ return const_cast<ID *>(get_evaluated_id(deg_graph, const_id));
+}
+
+} // namespace blender::deg
+
namespace deg = blender::deg;
struct Scene *DEG_get_input_scene(const Depsgraph *graph)
@@ -90,7 +133,7 @@ bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
return deg_graph->id_type_exist[BKE_idtype_idcode_to_index(id_type)] != 0;
}
-uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
+uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, const ID *id)
{
if (graph == nullptr) {
/* Happens when converting objects to mesh from a python script
@@ -102,7 +145,7 @@ uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
}
const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
- const deg::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id));
+ const deg::IDNode *id_node = deg_graph->find_id_node(deg::get_original_id(id));
if (id_node == nullptr) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
@@ -171,18 +214,7 @@ Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
{
- if (id == nullptr) {
- return nullptr;
- }
- /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
- * but here we never do assert, since we don't know nature of the
- * incoming ID data-block. */
- const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph;
- const deg::IDNode *id_node = deg_graph->find_id_node(id);
- if (id_node == nullptr) {
- return id;
- }
- return id_node->id_cow;
+ return deg::get_evaluated_id(reinterpret_cast<const deg::Depsgraph *>(depsgraph), id);
}
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
@@ -249,14 +281,7 @@ Object *DEG_get_original_object(Object *object)
ID *DEG_get_original_id(ID *id)
{
- if (id == nullptr) {
- return nullptr;
- }
- if (id->orig_id == nullptr) {
- return id;
- }
- BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- return (ID *)id->orig_id;
+ return deg::get_original_id(id);
}
bool DEG_is_original_id(const ID *id)