diff options
author | Jacques Lucke <jacques@blender.org> | 2022-06-22 11:56:21 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-06-22 11:56:21 +0300 |
commit | 2d0dc88209e166159bd0b68dc54103280b09193c (patch) | |
tree | 3875e9554c810d14fa3a490cbdf003472bd7ee3c /source/blender/depsgraph | |
parent | c57ed65cc88418e290401599e28d51f1acb5dfd9 (diff) | |
parent | a3d0f77ded1c982da93d61fac6942cfc67c9e599 (diff) |
Merge branch 'master' into deform-curves-with-surface
Diffstat (limited to 'source/blender/depsgraph')
14 files changed, 500 insertions, 80 deletions
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index a5693cb0fd7..3d539018cef 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC intern/builder/deg_builder_relations_view_layer.cc intern/builder/deg_builder_remove_noop.cc intern/builder/deg_builder_rna.cc + intern/builder/deg_builder_stack.cc intern/builder/deg_builder_transitive.cc intern/builder/pipeline.cc intern/builder/pipeline_all_objects.cc @@ -103,6 +104,7 @@ set(SRC intern/builder/deg_builder_relations_impl.h intern/builder/deg_builder_remove_noop.h intern/builder/deg_builder_rna.h + intern/builder/deg_builder_stack.h intern/builder/deg_builder_transitive.h intern/builder/pipeline.h intern/builder/pipeline_all_objects.h diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index ade75fa2f6f..12663e74d24 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -64,7 +64,7 @@ bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph); bool DEG_id_type_any_exists(const struct Depsgraph *depsgraph, short id_type); /** Get additional evaluation flags for the given ID. */ -uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id); +uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, const struct ID *id); /** Get additional mesh CustomData_MeshMasks flags for the given object. */ void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph, 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) |