diff options
Diffstat (limited to 'source/blender/depsgraph')
26 files changed, 591 insertions, 203 deletions
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index e30b77ea742..aee925ad8f8 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC_SYS set(SRC intern/builder/deg_builder.cc + intern/builder/deg_builder_cache.cc intern/builder/deg_builder_cycle.cc intern/builder/deg_builder_map.cc intern/builder/deg_builder_nodes.cc @@ -82,6 +83,7 @@ set(SRC DEG_depsgraph_query.h intern/builder/deg_builder.h + intern/builder/deg_builder_cache.h intern/builder/deg_builder_cycle.h intern/builder/deg_builder_map.h intern/builder/deg_builder_nodes.h diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index ef36dec6f34..b8e0ba51019 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -26,6 +26,7 @@ #include <cstring> #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_layer_types.h" #include "DNA_ID.h" #include "DNA_object_types.h" @@ -34,6 +35,8 @@ #include "BLI_ghash.h" #include "BLI_stack.h" +#include "BKE_action.h" + extern "C" { #include "BKE_animsys.h" } @@ -41,6 +44,7 @@ extern "C" { #include "intern/depsgraph.h" #include "intern/depsgraph_tag.h" #include "intern/depsgraph_type.h" +#include "intern/builder/deg_builder_cache.h" #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_id.h" @@ -51,70 +55,81 @@ extern "C" { namespace DEG { +bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base) +{ + Object *object_orig = base->base_orig->object; + IDNode *id_node = graph->find_id_node(&object_orig->id); + if (id_node == NULL) { + return false; + } + return id_node->has_base; +} + /******************************************************************************* * Base class for builders. */ -namespace { - -struct VisibilityCheckData { - eEvaluationMode eval_mode; - bool is_visibility_animated; -}; +DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache) + : bmain_(bmain), graph_(graph), cache_(cache) +{ +} -void visibility_animated_check_cb(ID * /*id*/, FCurve *fcu, void *user_data) +bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) { - VisibilityCheckData *data = reinterpret_cast<VisibilityCheckData *>(user_data); - if (data->is_visibility_animated) { - return; + /* Simple check: enabled bases are always part of dependency graph. */ + const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : + BASE_ENABLED_RENDER; + if (base->flag & base_flag) { + return true; } - if (data->eval_mode == DAG_EVAL_VIEWPORT) { - if (STREQ(fcu->rna_path, "hide_viewport")) { - data->is_visibility_animated = true; - } + /* More involved check: since we don't support dynamic changes in dependency graph topology and + * all visible objects are to be part of dependency graph, we pull all objects which has animated + * visibility. */ + Object *object = base->object; + AnimatedPropertyID property_id; + if (graph_->mode == DAG_EVAL_VIEWPORT) { + property_id = AnimatedPropertyID(&object->id, &RNA_Object, "hide_viewport"); } - else if (data->eval_mode == DAG_EVAL_RENDER) { - if (STREQ(fcu->rna_path, "hide_render")) { - data->is_visibility_animated = true; - } + else if (graph_->mode == DAG_EVAL_RENDER) { + property_id = AnimatedPropertyID(&object->id, &RNA_Object, "hide_render"); } -} - -bool is_object_visibility_animated(const Depsgraph *graph, Object *object) -{ - AnimData *anim_data = BKE_animdata_from_id(&object->id); - if (anim_data == NULL) { + else { + BLI_assert(!"Unknown evaluation mode."); return false; } - VisibilityCheckData data; - data.eval_mode = graph->mode; - data.is_visibility_animated = false; - BKE_fcurves_id_cb(&object->id, visibility_animated_check_cb, &data); - return data.is_visibility_animated; + return cache_->isPropertyAnimated(&object->id, property_id); } -} // namespace - -bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base) +bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel *pchan) { - const int base_flag = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : - BASE_ENABLED_RENDER; - if (base->flag & base_flag) { - return true; + BLI_assert(object->type == OB_ARMATURE); + if (pchan->bone == NULL) { + return false; } - if (is_object_visibility_animated(graph, base->object)) { + /* We don't really care whether segments are higher than 1 due to static user input (as in, + * rigger entered value like 3 manually), or due to animation. In either way we need to create + * special evaluation. */ + if (pchan->bone->segments > 1) { return true; } - return false; + bArmature *armature = static_cast<bArmature *>(object->data); + AnimatedPropertyID property_id(&armature->id, &RNA_Bone, pchan->bone, "bbone_segments"); + return cache_->isPropertyAnimated(&armature->id, property_id); } -DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), graph_(graph) +bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan) { + /* Proxies don't have BONE_SEGMENTS */ + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + return false; + } + return check_pchan_has_bbone(object, pchan); } -bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) +bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const char *bone_name) { - return deg_check_base_available_for_build(graph_, base); + const bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + return check_pchan_has_bbone_segments(object, pchan); } /******************************************************************************* diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 310944f2f28..224e3212d57 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -23,26 +23,35 @@ #pragma once +struct bPoseChannel; struct Base; struct Main; +struct Object; namespace DEG { struct Depsgraph; +class DepsgraphBuilderCache; class DepsgraphBuilder { public: - bool need_pull_base_into_graph(struct Base *base); + bool need_pull_base_into_graph(Base *base); + + bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan); + bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan); + bool check_pchan_has_bbone_segments(Object *object, const char *bone_name); protected: - DepsgraphBuilder(Main *bmain, Depsgraph *graph); + /* NOTE: The builder does NOT take ownership over any of those resources. */ + DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache); /* State which never changes, same for the whole builder time. */ Main *bmain_; Depsgraph *graph_; + DepsgraphBuilderCache *cache_; }; -bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base); -void deg_graph_build_finalize(struct Main *bmain, struct Depsgraph *graph); +bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base); +void deg_graph_build_finalize(Main *bmain, Depsgraph *graph); } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc new file mode 100644 index 00000000000..3df707e92c1 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc @@ -0,0 +1,186 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/builder/deg_builder_cache.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" + +#include "BLI_utildefines.h" + +extern "C" { +#include "BKE_animsys.h" +} + +namespace DEG { + +/* Animated property storage. */ + +AnimatedPropertyID::AnimatedPropertyID() : data(NULL), property_rna(NULL) +{ +} + +AnimatedPropertyID::AnimatedPropertyID(const PointerRNA *pointer_rna, + const PropertyRNA *property_rna) + : AnimatedPropertyID(*pointer_rna, property_rna) +{ +} + +AnimatedPropertyID::AnimatedPropertyID(const PointerRNA &pointer_rna, + const PropertyRNA *property_rna) + : data(pointer_rna.data), property_rna(property_rna) +{ +} + +AnimatedPropertyID::AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name) + : data(id) +{ + property_rna = RNA_struct_type_find_property(type, property_name); +} + +AnimatedPropertyID::AnimatedPropertyID(ID * /*id*/, + StructRNA *type, + void *data, + const char *property_name) + : data(data) +{ + property_rna = RNA_struct_type_find_property(type, property_name); +} + +bool AnimatedPropertyID::operator<(const AnimatedPropertyID &other) const +{ + if (data < other.data) { + return true; + } + else if (data == other.data) { + return property_rna < other.property_rna; + } + return false; +} + +namespace { + +struct AnimatedPropertyCallbackData { + PointerRNA pointer_rna; + AnimatedPropertyStorage *animated_property_storage; + DepsgraphBuilderCache *builder_cache; +}; + +void animated_property_cb(ID * /*id*/, FCurve *fcurve, void *data_v) +{ + if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') { + return; + } + AnimatedPropertyCallbackData *data = static_cast<AnimatedPropertyCallbackData *>(data_v); + /* Resolve property. */ + PointerRNA pointer_rna; + PropertyRNA *property_rna = NULL; + if (!RNA_path_resolve_property( + &data->pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna)) { + return; + } + /* Get storage for the ID. + * This is needed to deal with cases when nested datablock is animated by its parent. */ + AnimatedPropertyStorage *animated_property_storage = data->animated_property_storage; + if (pointer_rna.id.data != data->pointer_rna.id.data) { + animated_property_storage = data->builder_cache->ensureAnimatedPropertyStorage( + reinterpret_cast<ID *>(pointer_rna.id.data)); + } + /* Set the property as animated. */ + animated_property_storage->tagPropertyAsAnimated(&pointer_rna, property_rna); +} + +} // namespace + +AnimatedPropertyStorage::AnimatedPropertyStorage() : is_fully_initialized(false) +{ +} + +void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id) +{ + AnimatedPropertyCallbackData data; + RNA_id_pointer_create(id, &data.pointer_rna); + data.animated_property_storage = this; + data.builder_cache = builder_cache; + BKE_fcurves_id_cb(id, animated_property_cb, &data); +} + +void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id) +{ + animated_properties_set.insert(property_id); +} + +void AnimatedPropertyStorage::tagPropertyAsAnimated(const PointerRNA *pointer_rna, + const PropertyRNA *property_rna) +{ + tagPropertyAsAnimated(AnimatedPropertyID(pointer_rna, property_rna)); +} + +bool AnimatedPropertyStorage::isPropertyAnimated(const AnimatedPropertyID &property_id) +{ + return animated_properties_set.find(property_id) != animated_properties_set.end(); +} + +bool AnimatedPropertyStorage::isPropertyAnimated(const PointerRNA *pointer_rna, + const PropertyRNA *property_rna) +{ + return isPropertyAnimated(AnimatedPropertyID(pointer_rna, property_rna)); +} + +/* Builder cache itself. */ + +DepsgraphBuilderCache::DepsgraphBuilderCache() +{ +} + +DepsgraphBuilderCache::~DepsgraphBuilderCache() +{ + for (AnimatedPropertyStorageMap::value_type &iter : animated_property_storage_map_) { + AnimatedPropertyStorage *animated_property_storage = iter.second; + OBJECT_GUARDED_DELETE(animated_property_storage, AnimatedPropertyStorage); + } +} + +AnimatedPropertyStorage *DepsgraphBuilderCache::ensureAnimatedPropertyStorage(ID *id) +{ + AnimatedPropertyStorageMap::iterator it = animated_property_storage_map_.find(id); + if (it != animated_property_storage_map_.end()) { + return it->second; + } + AnimatedPropertyStorage *animated_property_storage = OBJECT_GUARDED_NEW(AnimatedPropertyStorage); + animated_property_storage_map_.insert(make_pair(id, animated_property_storage)); + return animated_property_storage; +} + +AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropertyStorage(ID *id) +{ + AnimatedPropertyStorage *animated_property_storage = ensureAnimatedPropertyStorage(id); + if (!animated_property_storage->is_fully_initialized) { + animated_property_storage->initializeFromID(this, id); + animated_property_storage->is_fully_initialized = true; + } + return animated_property_storage; +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.h b/source/blender/depsgraph/intern/builder/deg_builder_cache.h new file mode 100644 index 00000000000..949020e3a81 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.h @@ -0,0 +1,103 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/depsgraph_type.h" + +#include "RNA_access.h" + +struct ID; +struct PointerRNA; +struct PropertyRNA; + +namespace DEG { + +class DepsgraphBuilderCache; + +/* Identifier for animated property. */ +class AnimatedPropertyID { + public: + AnimatedPropertyID(); + AnimatedPropertyID(const PointerRNA *pointer_rna, const PropertyRNA *property_rna); + AnimatedPropertyID(const PointerRNA &pointer_rna, const PropertyRNA *property_rna); + AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name); + AnimatedPropertyID(ID *id, StructRNA *type, void *data, const char *property_name); + + bool operator<(const AnimatedPropertyID &other) const; + + /* Corresponds to PointerRNA.data. */ + void *data; + const PropertyRNA *property_rna; +}; + +class AnimatedPropertyStorage { + public: + AnimatedPropertyStorage(); + + void initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id); + + void tagPropertyAsAnimated(const AnimatedPropertyID &property_id); + void tagPropertyAsAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna); + + bool isPropertyAnimated(const AnimatedPropertyID &property_id); + bool isPropertyAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna); + + /* The storage is fully initialized from all F-Curves from corresponding ID. */ + bool is_fully_initialized; + + /* indexed by PointerRNA.data. */ + set<AnimatedPropertyID> animated_properties_set; +}; + +typedef map<ID *, AnimatedPropertyStorage *> AnimatedPropertyStorageMap; + +/* Cached data which can be re-used by multiple builders. */ +class DepsgraphBuilderCache { + public: + DepsgraphBuilderCache(); + ~DepsgraphBuilderCache(); + + /* Makes sure storage for animated properties exists and initialized for the given ID. */ + AnimatedPropertyStorage *ensureAnimatedPropertyStorage(ID *id); + AnimatedPropertyStorage *ensureInitializedAnimatedPropertyStorage(ID *id); + + /* Shortcuts to go through ensureInitializedAnimatedPropertyStorage and its + * isPropertyAnimated. + * + * NOTE: Avoid using for multiple subsequent lookups, query for the storage once, and then query + * the storage. + * + * TODO(sergey): Technically, this makes this class something else than just a cache, but what is + * the better name? */ + template<typename... Args> bool isPropertyAnimated(ID *id, Args... args) + { + AnimatedPropertyStorage *animated_property_storage = ensureInitializedAnimatedPropertyStorage( + id); + return animated_property_storage->isPropertyAnimated(args...); + } + + AnimatedPropertyStorageMap animated_property_storage_map_; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index af5c4e7130b..d11a60b77dd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -182,20 +182,16 @@ void solve_cycles(CyclesSolverState *state) OperationNode *to = (OperationNode *)rel->to; eCyclicCheckVisitedState to_state = get_node_visited_state(to); if (to_state == NODE_IN_STACK) { - printf("Dependency cycle detected:\n"); - printf(" '%s' depends on '%s' through '%s'\n", - to->full_identifier().c_str(), - node->full_identifier().c_str(), - rel->name); + string cycle_str = " " + to->full_identifier() + " depends on\n " + + node->full_identifier() + " via '" + rel->name + "'\n"; StackEntry *current = entry; while (current->node != to) { BLI_assert(current != NULL); - printf(" '%s' depends on '%s' through '%s'\n", - current->node->full_identifier().c_str(), - current->from->node->full_identifier().c_str(), - current->via_relation->name); + cycle_str += " " + current->from->node->full_identifier() + " via '" + + current->via_relation->name + "'\n"; current = current->from; } + printf("Dependency cycle detected:\n%s", cycle_str.c_str()); Relation *sacrificial_relation = select_relation_to_murder(rel, entry); sacrificial_relation->flag |= RELATION_FLAG_CYCLIC; ++state->num_cycles; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index b37ecb45ac8..b6822a89093 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -65,6 +65,7 @@ extern "C" { #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_animsys.h" +#include "BKE_cachefile.h" #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_curve.h" @@ -129,8 +130,10 @@ void free_copy_on_write_datablock(void *id_info_v) /* **** General purpose functions **** */ -DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) - : DepsgraphBuilder(bmain, graph), +DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, + Depsgraph *graph, + DepsgraphBuilderCache *cache) + : DepsgraphBuilder(bmain, graph, cache), scene_(NULL), view_layer_(NULL), view_layer_index_(-1), @@ -335,7 +338,7 @@ void DepsgraphNodeBuilder::begin_build() entry_tag.name = op_node->name; entry_tag.name_tag = op_node->name_tag; saved_entry_tags_.push_back(entry_tag); - }; + } GSET_FOREACH_END(); /* Make sure graph has no nodes left from previous state. */ @@ -526,6 +529,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { id_node->is_directly_visible |= is_visible; } + id_node->has_base |= (base_index != -1); return; } /* Create ID node for object and begin init. */ @@ -538,6 +542,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, else { id_node->is_directly_visible = is_visible; } + id_node->has_base |= (base_index != -1); /* Various flags, flushing from bases/collections. */ build_object_flags(base_index, object, linked_state); /* Transform. */ @@ -1177,12 +1182,6 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob op_node->set_as_exit(); /* Materials. */ if (object->totcol != 0) { - if (object->type == OB_MESH) { - add_operation_node(&object->id, - NodeType::SHADING, - OperationCode::SHADING, - function_bind(BKE_object_eval_update_shading, _1, object_cow)); - } for (int a = 1; a <= object->totcol; a++) { Material *ma = give_current_material(object, a); if (ma != NULL) { @@ -1441,7 +1440,7 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene) /* For now, just a plain wrapper? */ // TODO: create compositing component? // XXX: component type undefined! - //graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); + // graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); /* for now, nodetrees are just parameters; compositing occurs in internals * of renderer... */ @@ -1471,11 +1470,16 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) return; } ID *cache_file_id = &cache_file->id; + add_id_node(cache_file_id); + CacheFile *cache_file_cow = get_cow_datablock(cache_file); /* Animation, */ build_animdata(cache_file_id); build_parameters(cache_file_id); /* Cache evaluation itself. */ - add_operation_node(cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); + add_operation_node(cache_file_id, + NodeType::CACHE, + OperationCode::FILE_CACHE_UPDATE, + function_bind(BKE_cachefile_eval, bmain_, _1, cache_file_cow)); } void DepsgraphNodeBuilder::build_mask(Mask *mask) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index d88f5a792e0..cf7cf1a62d8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -69,6 +69,7 @@ namespace DEG { struct ComponentNode; struct Depsgraph; +class DepsgraphBuilderCache; struct IDNode; struct Node; struct OperationNode; @@ -76,7 +77,7 @@ struct TimeSourceNode; class DepsgraphNodeBuilder : public DepsgraphBuilder { public: - DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); + DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache); ~DepsgraphNodeBuilder(); /* For given original ID get ID which is created by CoW system. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 6f141bd7222..979e1a02e71 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -231,7 +231,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) function_bind(BKE_pose_bone_done, _1, object_cow, pchan_index)); /* B-Bone shape computation - the real last step if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { + if (check_pchan_has_bbone(object, pchan)) { op_node = add_operation_node( &object->id, NodeType::BONE, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 6d979724e7e..95c50c4f44e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -95,14 +95,14 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) { /* Ensure that both are in the map... */ if (BLI_ghash_haskey(map_, bone1) == false) { - //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); - //print_debug(); + // fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); + // print_debug(); return false; } if (BLI_ghash_haskey(map_, bone2) == false) { - //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); - //print_debug(); + // fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); + // print_debug(); return false; } @@ -116,13 +116,13 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); if (strcmp(v1, v2) == 0) { - //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); + // fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); return true; } } } - //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); + // fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); return false; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 87a8875f819..d3fd16d889f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -196,21 +196,12 @@ static OperationCode bone_target_opcode(ID *target, return OperationCode::BONE_DONE; } -static bool bone_has_segments(Object *object, const char *bone_name) -{ - /* Proxies don't have BONE_SEGMENTS */ - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - return false; - } - /* Only B-Bones have segments. */ - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); - return pchan && pchan->bone && pchan->bone->segments > 1; -} - /* **** General purpose functions **** */ -DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph) - : DepsgraphBuilder(bmain, graph), scene_(NULL), rna_node_query_(graph) +DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, + Depsgraph *graph, + DepsgraphBuilderCache *cache) + : DepsgraphBuilder(bmain, graph, cache), scene_(NULL), rna_node_query_(graph, this) { } @@ -1017,7 +1008,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, } /* if needs bbone shape, reference the segment computation */ if (BKE_constraint_target_uses_bbone(con, ct) && - bone_has_segments(ct->tar, ct->subtarget)) { + check_pchan_has_bbone_segments(ct->tar, ct->subtarget)) { opcode = OperationCode::BONE_SEGMENTS; } OperationKey target_key(&ct->tar->id, NodeType::BONE, ct->subtarget, opcode); @@ -1336,25 +1327,24 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) fcu->rna_path ? fcu->rna_path : "", fcu->array_index); const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { + if (GS(id->name) == ID_AR && STRPREFIX(rna_path, "bones[")) { /* Drivers on armature-level bone settings (i.e. bbone stuff), * which will affect the evaluation of corresponding pose bones. */ - IDNode *arm_node = graph_->find_id_node(id); char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); - if (arm_node != NULL && bone_name != NULL) { + if (bone_name != NULL) { /* Find objects which use this, and make their eval callbacks * depend on this. */ - for (Relation *rel : arm_node->outlinks) { - IDNode *to_node = (IDNode *)rel->to; - /* We only care about objects with pose data which use this. */ + for (IDNode *to_node : graph_->id_nodes) { if (GS(to_node->id_orig->name) == ID_OB) { Object *object = (Object *)to_node->id_orig; - // NOTE: object->pose may be NULL - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); - if (pchan != NULL) { - OperationKey bone_key( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); - add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone"); + /* We only care about objects with pose data which use this. */ + if (object->data == id && object->pose != NULL) { + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + if (pchan != NULL) { + OperationKey bone_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone"); + } } } } @@ -1411,27 +1401,34 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - if (dtar->id == NULL) { + ID *target_id = dtar->id; + if (target_id == NULL) { continue; } - build_id(dtar->id); - build_driver_id_property(dtar->id, dtar->rna_path); - /* Initialize relations coming to proxy_from. */ - Object *proxy_from = NULL; - if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { - proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); + build_id(target_id); + build_driver_id_property(target_id, dtar->rna_path); + /* Look up the proxy - matches dtar_id_ensure_proxy_from during evaluation. */ + Object *object = NULL; + if (GS(target_id->name) == ID_OB) { + object = (Object *)target_id; + if (object->proxy_from != NULL) { + /* Redirect the target to the proxy, like in evaluation. */ + object = object->proxy_from; + target_id = &object->id; + /* Prepare the redirected target. */ + build_id(target_id); + build_driver_id_property(target_id, dtar->rna_path); + } } /* Special handling for directly-named bones. */ - if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (((Object *)dtar->id)->type == OB_ARMATURE) && + if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (object && object->type == OB_ARMATURE) && (dtar->pchan_name[0])) { - Object *object = (Object *)dtar->id; bPoseChannel *target_pchan = BKE_pose_channel_find_name(object->pose, dtar->pchan_name); if (target_pchan == NULL) { continue; } OperationKey variable_key( - dtar->id, NodeType::BONE, target_pchan->name, OperationCode::BONE_DONE); + target_id, NodeType::BONE, target_pchan->name, OperationCode::BONE_DONE); if (is_same_bone_dependency(variable_key, self_key)) { continue; } @@ -1439,17 +1436,17 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) } else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { /* Get node associated with the object's transforms. */ - if (dtar->id == id) { + if (target_id == id) { /* Ignore input dependency if we're driving properties of * the same ID, otherwise we'll be ending up in a cyclic * dependency here. */ continue; } - OperationKey target_key(dtar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + OperationKey target_key(target_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); add_relation(target_key, driver_key, "Target -> Driver"); } else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { - RNAPathKey variable_exit_key(dtar->id, dtar->rna_path, RNAPointerSource::EXIT); + RNAPathKey variable_exit_key(target_id, dtar->rna_path, RNAPointerSource::EXIT); if (RNA_pointer_is_null(&variable_exit_key.ptr)) { continue; } @@ -1458,12 +1455,6 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) continue; } add_relation(variable_exit_key, driver_key, "RNA Target -> Driver"); - if (proxy_from != NULL) { - RNAPathKey proxy_from_variable_key( - &proxy_from->id, dtar->rna_path, RNAPointerSource::EXIT); - RNAPathKey variable_entry_key(dtar->id, dtar->rna_path, RNAPointerSource::ENTRY); - add_relation(proxy_from_variable_key, variable_entry_key, "Proxy From -> Variable"); - } } else { /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this @@ -1904,12 +1895,6 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) Material *ma = give_current_material(object, a); if (ma != NULL) { build_material(ma); - - if (object->type == OB_MESH) { - OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); - OperationKey shading_key(&object->id, NodeType::SHADING, OperationCode::SHADING); - add_relation(material_key, shading_key, "Material Update"); - } } } } @@ -1923,12 +1908,6 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) OperationKey obdata_ubereval_key( &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); - if (object->totcol != 0 && object->type == OB_MESH) { - ComponentKey object_shading_key(&object->id, NodeType::SHADING); - Relation *rel = add_relation( - obdata_ubereval_key, object_shading_key, "Object Geometry batch Update"); - rel->flag |= RELATION_FLAG_NO_FLUSH; - } } if (object->type == OB_MBALL) { Object *mom = BKE_mball_basis_find(scene_, object); @@ -2243,6 +2222,14 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) ComponentKey datablock_key(&cache_file->id, NodeType::CACHE); add_relation(animation_key, datablock_key, "Datablock Animation"); } + + /* Cache file updates */ + if (cache_file->is_sequence) { + OperationKey cache_update_key( + &cache_file->id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); + TimeSourceKey time_src_key; + add_relation(time_src_key, cache_update_key, "TimeSrc -> Cache File Eval"); + } } void DepsgraphRelationBuilder::build_mask(Mask *mask) @@ -2350,7 +2337,8 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) continue; } int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); - if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) { + if ((id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) || + (id_type == ID_CF && comp_node->type == NodeType::CACHE)) { rel_flag &= ~RELATION_FLAG_NO_FLUSH; } /* Notes on exceptions: diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 5b2d34a270c..90bdb9bae65 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -86,6 +86,7 @@ namespace DEG { struct ComponentNode; struct DepsNodeHandle; struct Depsgraph; +class DepsgraphBuilderCache; struct IDNode; struct Node; struct OperationNode; @@ -155,7 +156,7 @@ struct RNAPathKey { class DepsgraphRelationBuilder : public DepsgraphBuilder { public: - DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph); + DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache); void begin_build(); 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 1d222258449..fadce685d31 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -83,46 +83,34 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); /* Never cleanup before solver is run. */ add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE); + /* The ITASC solver currently accesses the target transforms in init tree :( + * TODO: Fix ITASC and remove this. + */ + bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC); + OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key; /* IK target */ /* TODO(sergey): This should get handled as part of the constraint code. */ if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matrices in the - * depsgraph, we create dependency between target object and pose eval - * component. - * - * This way we ensuring the whole subtree is updated from scratch - * without need of intermediate matrices. This is an overkill, but good - * enough for testing IK solver. */ - ComponentKey pose_key(&object->id, NodeType::EVAL_POSE); + /* Different object - requires its transform. */ + if (data->tar != object) { + ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); + add_relation(target_key, target_dependent_key, con->name); + } + /* Subtarget references: */ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { - /* TODO(sergey): This is only for until granular update stores - * intermediate result. */ - if (data->tar != object) { - /* Different armature - can just read the results. */ - ComponentKey target_key(&data->tar->id, NodeType::BONE, data->subtarget); - add_relation(target_key, pose_key, con->name); - } - else { - /* Same armature - we'll use the ready state only, just in case - * this bone is in the chain we're solving. */ - OperationKey target_key( - &data->tar->id, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE); - add_relation(target_key, solver_key, con->name); - } + /* Bone - use the final transformation. */ + OperationKey target_key( + &data->tar->id, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE); + add_relation(target_key, target_dependent_key, con->name); } else if (data->subtarget[0] && ELEM(data->tar->type, OB_MESH, OB_LATTICE)) { /* Vertex group target. */ /* NOTE: for now, we don't need to represent vertex groups * separately. */ ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); + add_relation(target_key, target_dependent_key, con->name); add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); } - else { - /* Standard Object Target. */ - ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); - add_relation(target_key, pose_key, con->name); - } if (data->tar == object && data->subtarget[0]) { /* Prevent target's constraints from linking to anything from same * chain that it controls. */ @@ -132,22 +120,26 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, /* Pole Target. */ /* TODO(sergey): This should get handled as part of the constraint code. */ if (data->poletar != NULL) { + /* Different object - requires its transform. */ + if (data->poletar != object) { + ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); + add_relation(target_key, target_dependent_key, con->name); + } + /* Subtarget references: */ if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - ComponentKey target_key(&data->poletar->id, NodeType::BONE, data->polesubtarget); - add_relation(target_key, solver_key, con->name); + /* Bone - use the final transformation. */ + OperationKey target_key( + &data->poletar->id, NodeType::BONE, data->polesubtarget, OperationCode::BONE_DONE); + add_relation(target_key, target_dependent_key, con->name); } else if (data->polesubtarget[0] && ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) { /* Vertex group target. */ /* NOTE: for now, we don't need to represent vertex groups * separately. */ ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); + add_relation(target_key, target_dependent_key, con->name); add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); } - else { - ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); - add_relation(target_key, solver_key, con->name); - } } DEG_DEBUG_PRINTF((::Depsgraph *)graph_, BUILD, @@ -382,7 +374,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) * to done, with transitive reduction removing this one. */ add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); /* B-Bone shape is the real final step after Done if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { + if (check_pchan_has_bbone(object, pchan)) { OperationKey bone_segments_key( &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); /* B-Bone shape depends on the final position of the bone. */ @@ -442,7 +434,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE); /* Make sure bone in the proxy is not done before it's FROM is done. */ - if (pchan->bone && pchan->bone->segments > 1) { + if (check_pchan_has_bbone(object, pchan)) { OperationKey from_bone_segments_key( &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); add_relation(from_bone_segments_key, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 810d3ee3f66..1238cdc70c6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -45,6 +45,7 @@ extern "C" { #include "RNA_access.h" #include "intern/depsgraph.h" +#include "intern/builder/deg_builder.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" @@ -130,8 +131,10 @@ void ghash_id_data_free_func(void *value) } // namespace -RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph) - : depsgraph_(depsgraph), id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) +RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder) + : depsgraph_(depsgraph), + builder_(builder), + id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) { } @@ -194,20 +197,20 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.type = NodeType::BONE; node_identifier.component_name = pchan->name; /* But B-Bone properties should connect to the actual operation. */ - if (!ELEM(NULL, pchan->bone, prop) && pchan->bone->segments > 1 && - STRPREFIX(RNA_property_identifier(prop), "bbone_")) { + Object *object = reinterpret_cast<Object *>(node_identifier.id); + if (!ELEM(NULL, pchan->bone, prop) && STRPREFIX(RNA_property_identifier(prop), "bbone_") && + builder_->check_pchan_has_bbone_segments(object, pchan)) { node_identifier.operation_code = OperationCode::BONE_SEGMENTS; } } return node_identifier; } else if (ptr->type == &RNA_Bone) { - const Bone *bone = static_cast<const Bone *>(ptr->data); - /* Armature-level bone, but it ends up going to bone component - * anyway. */ - // NOTE: the ID in this case will end up being bArmature. - node_identifier.type = NodeType::BONE; - node_identifier.component_name = bone->name; + /* Armature-level bone mapped to Armature Eval, and thus Pose Init. + * Drivers have special code elsewhere that links them to the pose + * bone components, instead of using this generic code. */ + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::ARMATURE_EVAL; return node_identifier; } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index e8dbd7fb523..26d7963e0a8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -36,6 +36,7 @@ namespace DEG { struct Depsgraph; struct Node; class RNANodeQueryIDData; +class DepsgraphBuilder; /* For queries which gives operation node or key defines whether we are * interested in a result of the given property or whether we are linking some @@ -72,13 +73,14 @@ class RNANodeIdentifier { * dependency graph which satisfies given RNA pointer or RAN path. */ class RNANodeQuery { public: - RNANodeQuery(Depsgraph *depsgraph); + RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder); ~RNANodeQuery(); Node *find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source); protected: Depsgraph *depsgraph_; + DepsgraphBuilder *builder_; /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ GHash *id_data_map_; diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index abd3b398cb7..068a04943e6 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -122,8 +122,9 @@ static int deg_debug_node_color_index(const Node *node) return 5; case NodeType::OPERATION: { OperationNode *op_node = (OperationNode *)node; - if (op_node->is_noop()) + if (op_node->is_noop()) { return 8; + } break; } @@ -485,16 +486,19 @@ static bool deg_debug_graphviz_is_owner(const Node *node, const Node *other) switch (node->get_class()) { case NodeClass::COMPONENT: { ComponentNode *comp_node = (ComponentNode *)node; - if (comp_node->owner == other) + if (comp_node->owner == other) { return true; + } break; } case NodeClass::OPERATION: { OperationNode *op_node = (OperationNode *)node; - if (op_node->owner == other) + if (op_node->owner == other) { return true; - else if (op_node->owner->owner == other) + } + else if (op_node->owner->owner == other) { return true; + } break; } default: diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index e4c84264960..dd2979160cd 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -46,6 +46,7 @@ extern "C" { #include "DEG_depsgraph_build.h" #include "builder/deg_builder.h" +#include "builder/deg_builder_cache.h" #include "builder/deg_builder_cycle.h" #include "builder/deg_builder_nodes.h" #include "builder/deg_builder_relations.h" @@ -238,14 +239,15 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph, BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); BLI_assert(deg_graph->scene == scene); BLI_assert(deg_graph->view_layer == view_layer); + DEG::DepsgraphBuilderCache builder_cache; /* Generate all the nodes in the graph first */ - DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph); + DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache); node_builder.begin_build(); node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); node_builder.end_build(); /* Hook up relationships between operations - to determine evaluation * order. */ - DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph); + DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache); relation_builder.begin_build(); relation_builder.build_view_layer(scene, view_layer); relation_builder.build_copy_on_write_relations(); diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index e795bed144d..6253d31b8aa 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -237,10 +237,12 @@ void DEG_stats_simple(const Depsgraph *graph, tot_rels += time_source->inlinks.size(); } - if (r_relations) + if (r_relations) { *r_relations = tot_rels; - if (r_outer) + } + if (r_outer) { *r_outer = tot_outer; + } } } diff --git a/source/blender/depsgraph/intern/depsgraph_query_filter.cc b/source/blender/depsgraph/intern/depsgraph_query_filter.cc index 987e9330d35..a02ced286eb 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_filter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_filter.cc @@ -162,7 +162,7 @@ static void deg_filter_remove_unwanted_ids(Depsgraph *graph, GSet *retained_ids) } } -} //namespace DEG +} // namespace DEG /* *************************************************** */ /* Graph Filtering API */ diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index 51ed31b8e25..cce64116907 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -37,6 +37,7 @@ #include <vector> #include <algorithm> #include <map> +#include <set> #include <unordered_map> struct Depsgraph; @@ -48,6 +49,7 @@ namespace DEG { /* Commonly used types. */ using std::map; using std::pair; +using std::set; using std::string; using std::unordered_map; using std::vector; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 01b712fcd87..2f153e585d3 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -368,8 +368,7 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph, void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *view_layer) { ListBase enabled_bases = {NULL, NULL}; - LISTBASE_FOREACH_MUTABLE(Base *, base, &view_layer->object_bases) - { + LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) { /* TODO(sergey): Would be cool to optimize this somehow, or make it so * builder tags bases. * @@ -381,7 +380,7 @@ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *vie * points to is not yet copied. This is dangerous access from evaluated * domain to original one, but this is how the entire copy-on-write works: * it does need to access original for an initial copy. */ - const bool is_object_enabled = deg_check_base_available_for_build(depsgraph, base->base_orig); + const bool is_object_enabled = deg_check_base_in_depsgraph(depsgraph, base); if (is_object_enabled) { BLI_addtail(&enabled_bases, base); } @@ -634,6 +633,40 @@ void update_modifiers_orig_pointers(const Object *object_orig, Object *object_co &object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data); } +void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *strips_cow) +{ + NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first); + NlaStrip *strip_cow = reinterpret_cast<NlaStrip *>(strips_cow->first); + while (strip_orig != NULL) { + strip_cow->orig_strip = strip_orig; + update_nla_strips_orig_pointers(&strip_orig->strips, &strip_cow->strips); + strip_cow = strip_cow->next; + strip_orig = strip_orig->next; + } +} + +void update_nla_tracks_orig_pointers(const ListBase *tracks_orig, ListBase *tracks_cow) +{ + NlaTrack *track_orig = reinterpret_cast<NlaTrack *>(tracks_orig->first); + NlaTrack *track_cow = reinterpret_cast<NlaTrack *>(tracks_cow->first); + while (track_orig != NULL) { + update_nla_strips_orig_pointers(&track_orig->strips, &track_cow->strips); + track_cow = track_cow->next; + track_orig = track_orig->next; + } +} + +void update_animation_data_after_copy(const ID *id_orig, ID *id_cow) +{ + const AnimData *anim_data_orig = BKE_animdata_from_id(const_cast<ID *>(id_orig)); + if (anim_data_orig == NULL) { + return; + } + AnimData *anim_data_cow = BKE_animdata_from_id(id_cow); + BLI_assert(anim_data_cow != NULL); + update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks); +} + /* Do some special treatment of data transfer from original ID to it's * CoW complementary part. * @@ -644,6 +677,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, ID *id_cow) { const ID_Type type = GS(id_orig->name); + update_animation_data_after_copy(id_orig, id_cow); switch (type) { case ID_OB: { /* Ensure we don't drag someone's else derived mesh to the @@ -841,6 +875,9 @@ class ModifierDataBackupID { /* Storage for backed up runtime modifier data. */ typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup; +/* Storage for backed up pose channel runtime data. */ +typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup; + struct ObjectRuntimeBackup { ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0) { @@ -853,16 +890,19 @@ struct ObjectRuntimeBackup { * pointers. */ void init_from_object(Object *object); void backup_modifier_runtime_data(Object *object); + void backup_pose_channel_runtime_data(Object *object); /* Restore all fields to the given object. */ void restore_to_object(Object *object); /* NOTE: Will free all runtime data which has not been restored. */ void restore_modifier_runtime_data(Object *object); + void restore_pose_channel_runtime_data(Object *object); Object_Runtime runtime; short base_flag; unsigned short base_local_view_bits; ModifierRuntimeDataBackup modifier_runtime_data; + PoseChannelRuntimeDataBackup pose_channel_runtime_data; }; void ObjectRuntimeBackup::init_from_object(Object *object) @@ -884,6 +924,8 @@ void ObjectRuntimeBackup::init_from_object(Object *object) base_local_view_bits = object->base_local_view_bits; /* Backup tuntime data of all modifiers. */ backup_modifier_runtime_data(object); + /* Backup runtime data of all pose channels. */ + backup_pose_channel_runtime_data(object); } inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data) @@ -905,6 +947,19 @@ void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) } } +void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime; + BKE_pose_channel_runtime_reset(&pchan->runtime); + } + } + } +} + void ObjectRuntimeBackup::restore_to_object(Object *object) { Mesh *mesh_orig = object->runtime.mesh_orig; @@ -941,6 +996,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object) /* Restore modifier's runtime data. * NOTE: Data of unused modifiers will be freed there. */ restore_modifier_runtime_data(object); + restore_pose_channel_runtime_data(object); } void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) @@ -967,6 +1023,26 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) } } +void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + PoseChannelRuntimeDataBackup::iterator runtime_data_iterator = + pose_channel_runtime_data.find(pchan->orig_pchan); + if (runtime_data_iterator != pose_channel_runtime_data.end()) { + pchan->runtime = runtime_data_iterator->second; + pose_channel_runtime_data.erase(runtime_data_iterator); + } + } + } + } + for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) { + BKE_pose_channel_runtime_free(&value.second); + } +} + class RuntimeBackup { public: RuntimeBackup() : drawdata_ptr(NULL) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index c913bb0f3f2..b174941e3bb 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -74,8 +74,7 @@ void deg_free_copy_on_write_datablock(struct ID *id_cow); void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, const struct IDNode *id_node); /* Check that given ID is properly expanded and does not have any shallow - * copies inside. - */ + * copies inside. */ bool deg_validate_copy_on_write_datablock(ID *id_cow); /* Tag given ID block as being copy-on-wtritten. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index dc7ca371de3..ceec62e278b 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -335,7 +335,7 @@ void BoneComponentNode::init(const ID *id, const char *subdata) /* name of component comes is bone name */ /* TODO(sergey): This sets name to an empty string because subdata is * empty. Is it a bug? */ - //this->name = subdata; + // this->name = subdata; /* bone-specific node data */ Object *object = (Object *)id; diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 77e8f4f37e0..c5b9c56bcf0 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -111,6 +111,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata)) linked_state = DEG_ID_LINKED_INDIRECTLY; is_directly_visible = true; is_collection_fully_expanded = false; + has_base = false; visible_components_mask = 0; previously_visible_components_mask = 0; diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 34d78e29060..b4351ec988c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -96,6 +96,9 @@ struct IDNode : public Node { * recursed into. */ bool is_collection_fully_expanded; + /* Is used to figure out whether object came to the dependency graph via a base. */ + bool has_base; + IDComponentsMask visible_components_mask; IDComponentsMask previously_visible_components_mask; diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 54a5ecef35c..154563303ad 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -208,14 +208,11 @@ string OperationNode::identifier() const * used for logging and debug prints. */ string OperationNode::full_identifier() const { - string owner_str = ""; - if (owner->type == NodeType::BONE) { - owner_str = string(owner->owner->name) + "." + owner->name; + string owner_str = owner->owner->name; + if (owner->type == NodeType::BONE || !owner->name.empty()) { + owner_str += "/" + owner->name; } - else { - owner_str = owner->owner->name; - } - return owner_str + "." + identifier(); + return owner_str + "/" + identifier(); } void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source) |