Merge branch 'master' into blender2.8
[blender.git] / source / blender / depsgraph / intern / depsgraph.cc
index 241c3fb9ac3f1a5bd244a57df2c41d4660660ddf..2a24d72eb67f99ceefe776b98ec954b9b43408dd 100644 (file)
@@ -48,15 +48,18 @@ extern "C" {
 #include "DNA_object_types.h"
 #include "DNA_sequence_types.h"
 
-#include "BKE_depsgraph.h"
-
 #include "RNA_access.h"
+
+#include "BKE_scene.h"
 }
 
 #include <algorithm>
 #include <cstring>
 
 #include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
 
 #include "intern/nodes/deg_node.h"
 #include "intern/nodes/deg_node_component.h"
@@ -71,7 +74,6 @@ namespace DEG {
 
 static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
 static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
-static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL;
 
 /* TODO(sergey): Find a better place for this. */
 template <typename T>
@@ -81,14 +83,24 @@ static void remove_from_vector(vector<T> *vector, const T& value)
                      vector->end());
 }
 
-Depsgraph::Depsgraph()
+Depsgraph::Depsgraph(Scene *scene,
+                     ViewLayer *view_layer,
+                     eEvaluationMode mode)
   : time_source(NULL),
-    need_update(false),
-    layers(0)
+    need_update(true),
+    scene(scene),
+    view_layer(view_layer),
+    mode(mode),
+    ctime(BKE_scene_frame_get(scene)),
+    scene_cow(NULL),
+    is_active(false)
 {
        BLI_spin_init(&lock);
        id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
        entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
+       debug_flags = G.debug;
+       memset(id_type_updated, 0, sizeof(id_type_updated));
+       memset(physics_relations, 0, sizeof(physics_relations));
 }
 
 Depsgraph::~Depsgraph()
@@ -214,6 +226,10 @@ static bool pointer_to_component_node_criteria(
                *subdata = seq->name; // xxx?
                return true;
        }
+       else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
+               *type = DEG_NODE_TYPE_SHADING;
+               return true;
+       }
        else if (ptr->type == &RNA_Curve) {
                *id = (ID *)ptr->id.data;
                *type = DEG_NODE_TYPE_GEOMETRY;
@@ -274,12 +290,6 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
 
 /* Node Management ---------------------------- */
 
-static void id_node_deleter(void *value)
-{
-       IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
-       OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
-}
-
 TimeSourceDepsNode *Depsgraph::add_time_source()
 {
        if (time_source == NULL) {
@@ -299,23 +309,60 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const
        return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
 }
 
-IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
+IDDepsNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
 {
+       BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) == 0);
        IDDepsNode *id_node = find_id_node(id);
        if (!id_node) {
                DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_ID_REF);
-               id_node = (IDDepsNode *)factory->create_node(id, "", name);
-               /* register */
+               id_node = (IDDepsNode *)factory->create_node(id, "", id->name);
+               id_node->init_copy_on_write(id_cow_hint);
+               /* Register node in ID hash.
+                *
+                * NOTE: We address ID nodes by the original ID pointer they are
+                * referencing to.
+                */
                BLI_ghash_insert(id_hash, id, id_node);
                id_nodes.push_back(id_node);
        }
        return id_node;
 }
 
+void Depsgraph::clear_id_nodes_conditional(const std::function <bool (ID_Type id_type)>& filter)
+{
+       foreach (IDDepsNode *id_node, id_nodes) {
+               if (id_node->id_cow == NULL) {
+                       /* This means builder "stole" ownership of the copy-on-written
+                        * datablock for her own dirty needs.
+                        */
+                       continue;
+               }
+               if (!deg_copy_on_write_is_expanded(id_node->id_cow)) {
+                       continue;
+               }
+               const ID_Type id_type = GS(id_node->id_cow->name);
+               if (filter(id_type)) {
+                       id_node->destroy();
+               }
+       }
+}
+
 void Depsgraph::clear_id_nodes()
 {
-       BLI_ghash_clear(id_hash, NULL, id_node_deleter);
+       /* Free memory used by ID nodes. */
+
+       /* Stupid workaround to ensure we free IDs in a proper order. */
+       clear_id_nodes_conditional([](ID_Type id_type) { return id_type == ID_SCE; });
+       clear_id_nodes_conditional([](ID_Type id_type) { return id_type != ID_PA; });
+
+       foreach (IDDepsNode *id_node, id_nodes) {
+               OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+       }
+       /* Clear containers. */
+       BLI_ghash_clear(id_hash, NULL, NULL);
        id_nodes.clear();
+       /* Clear physics relation caches. */
+       deg_clear_physics_relations(this);
 }
 
 /* Add new relationship between two nodes. */
@@ -339,7 +386,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
        if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
                IDDepsNode *id_to = to->owner->owner;
                IDDepsNode *id_from = from->owner->owner;
-               if (id_to != id_from && (id_to->id->recalc & ID_RECALC_ALL)) {
+               if (id_to != id_from && (id_to->id_orig->recalc & ID_RECALC_ALL)) {
                        if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
                                id_from->tag_update(this);
                                id_from->eval_flags |= DAG_EVAL_NEED_CPU;
@@ -433,9 +480,9 @@ void DepsRelation::unlink()
 void Depsgraph::add_entry_tag(OperationDepsNode *node)
 {
        /* Sanity check. */
-       if (!node)
+       if (node == NULL) {
                return;
-
+       }
        /* Add to graph-level set of directly modified nodes to start searching from.
         * NOTE: this is necessary since we have several thousand nodes to play with...
         */
@@ -451,17 +498,46 @@ void Depsgraph::clear_all_nodes()
        }
 }
 
-void deg_editors_id_update(Main *bmain, ID *id)
+ID *Depsgraph::get_cow_id(const ID *id_orig) const
+{
+       IDDepsNode *id_node = find_id_node(id_orig);
+       if (id_node == NULL) {
+               /* This function is used from places where we expect ID to be either
+                * already a copy-on-write version or have a corresponding copy-on-write
+                * version.
+                *
+                * We try to enforce that in debug builds, for for release we play a bit
+                * safer game here.
+                */
+               if ((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+                       /* TODO(sergey): This is nice sanity check to have, but it fails
+                        * in following situations:
+                        *
+                        * - Material has link to texture, which is not needed by new
+                        *   shading system and hence can be ignored at construction.
+                        * - Object or mesh has material at a slot which is not used (for
+                        *   example, object has material slot by materials are set to
+                        *   object data).
+                        */
+                       // BLI_assert(!"Request for non-existing copy-on-write ID");
+               }
+               return (ID *)id_orig;
+       }
+       return id_node->id_cow;
+}
+
+void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id)
 {
        if (deg_editor_update_id_cb != NULL) {
-               deg_editor_update_id_cb(bmain, id);
+               deg_editor_update_id_cb(update_ctx, id);
        }
 }
 
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
+                              bool updated)
 {
        if (deg_editor_update_scene_cb != NULL) {
-               deg_editor_update_scene_cb(bmain, scene, updated);
+               deg_editor_update_scene_cb(update_ctx, updated);
        }
 }
 
@@ -496,9 +572,14 @@ string deg_color_end(void)
 /* Public Graph API */
 
 /* Initialize a new Depsgraph */
-Depsgraph *DEG_graph_new()
-{
-       DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph);
+Depsgraph *DEG_graph_new(Scene *scene,
+                         ViewLayer *view_layer,
+                         eEvaluationMode mode)
+{
+       DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph,
+                                                          scene,
+                                                          view_layer,
+                                                          mode);
        return reinterpret_cast<Depsgraph *>(deg_depsgraph);
 }
 
@@ -512,32 +593,68 @@ void DEG_graph_free(Depsgraph *graph)
 
 /* Set callbacks which are being called when depsgraph changes. */
 void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
-                               DEG_EditorUpdateSceneCb scene_func,
-                               DEG_EditorUpdateScenePreCb scene_pre_func)
+                               DEG_EditorUpdateSceneCb scene_func)
 {
        DEG::deg_editor_update_id_cb = id_func;
        DEG::deg_editor_update_scene_cb = scene_func;
-       DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
 }
 
-void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
+bool DEG_is_active(const struct Depsgraph *depsgraph)
 {
-       if (DEG::deg_editor_update_scene_pre_cb != NULL) {
-               DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
+       if (depsgraph == NULL) {
+               /* Happens for such cases as work object in what_does_obaction(),
+                * and sine render pipeline parts. Shouldn't really be accepting
+                * NULL depsgraph, but is quite hard to get proper one in those
+                * cases.
+                */
+               return false;
        }
+       const DEG::Depsgraph *deg_graph =
+               reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
+       return deg_graph->is_active;
+}
+
+void DEG_make_active(struct Depsgraph *depsgraph)
+{
+       DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+       deg_graph->is_active = true;
+       /* TODO(sergey): Copy data from evaluated state to original. */
+}
+
+void DEG_make_inactive(struct Depsgraph *depsgraph)
+{
+       DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+       deg_graph->is_active = false;
 }
 
 /* Evaluation and debug */
 
-void DEG_debug_print_eval(const char *function_name,
+static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph)
+{
+       const char *name = DEG_debug_name_get(depsgraph);
+       if (name[0] == '\0') {
+               return "";
+       }
+       return "[" + DEG::string(name) + "]: ";
+}
+
+void DEG_debug_print_begin(struct Depsgraph *depsgraph)
+{
+       fprintf(stdout, "%s",
+               depsgraph_name_for_logging(depsgraph).c_str());
+}
+
+void DEG_debug_print_eval(struct Depsgraph *depsgraph,
+                          const char *function_name,
                           const char *object_name,
                           const void *object_address)
 {
-       if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+       if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
                return;
        }
        fprintf(stdout,
-               "%s on %s %s(%p)%s\n",
+               "%s%s on %s %s(%p)%s\n",
+               depsgraph_name_for_logging(depsgraph).c_str(),
                function_name,
                object_name,
                DEG::deg_color_for_pointer(object_address).c_str(),
@@ -546,18 +663,20 @@ void DEG_debug_print_eval(const char *function_name,
        fflush(stdout);
 }
 
-void DEG_debug_print_eval_subdata(const char *function_name,
+void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph,
+                                  const char *function_name,
                                   const char *object_name,
                                   const void *object_address,
                                   const char *subdata_comment,
                                   const char *subdata_name,
                                   const void *subdata_address)
 {
-       if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+       if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
                return;
        }
        fprintf(stdout,
-               "%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+               "%s%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+               depsgraph_name_for_logging(depsgraph).c_str(),
                function_name,
                object_name,
                DEG::deg_color_for_pointer(object_address).c_str(),
@@ -571,7 +690,8 @@ void DEG_debug_print_eval_subdata(const char *function_name,
        fflush(stdout);
 }
 
-void DEG_debug_print_eval_subdata_index(const char *function_name,
+void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
+                                        const char *function_name,
                                         const char *object_name,
                                         const void *object_address,
                                         const char *subdata_comment,
@@ -579,11 +699,12 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
                                         const void *subdata_address,
                                         const int subdata_index)
 {
-       if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+       if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
                return;
        }
        fprintf(stdout,
-               "%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
+               "%s%s on %s %s(%p)%s %s %s[%d] %s(%p)%s\n",
+               depsgraph_name_for_logging(depsgraph).c_str(),
                function_name,
                object_name,
                DEG::deg_color_for_pointer(object_address).c_str(),
@@ -598,16 +719,45 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
        fflush(stdout);
 }
 
-void DEG_debug_print_eval_time(const char *function_name,
+void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
+                                       const char *function_name,
+                                       const char *object_name,
+                                       const void *object_address,
+                                       const char *parent_comment,
+                                       const char *parent_name,
+                                       const void *parent_address)
+{
+       if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+               return;
+       }
+       fprintf(stdout,
+               "%s%s on %s %s(%p) [%s] %s %s %s(%p)%s\n",
+               depsgraph_name_for_logging(depsgraph).c_str(),
+               function_name,
+               object_name,
+               DEG::deg_color_for_pointer(object_address).c_str(),
+               object_address,
+               DEG::deg_color_end().c_str(),
+               parent_comment,
+               parent_name,
+               DEG::deg_color_for_pointer(parent_address).c_str(),
+               parent_address,
+               DEG::deg_color_end().c_str());
+       fflush(stdout);
+}
+
+void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
+                               const char *function_name,
                                const char *object_name,
                                const void *object_address,
                                float time)
 {
-       if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+       if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
                return;
        }
        fprintf(stdout,
-               "%s on %s %s(%p)%s at time %f\n",
+               "%s%s on %s %s(%p)%s at time %f\n",
+               depsgraph_name_for_logging(depsgraph).c_str(),
                function_name,
                object_name,
                DEG::deg_color_for_pointer(object_address).c_str(),