diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-04-12 10:47:51 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-04-12 12:05:18 +0300 |
commit | 15698f99070f4d196dbfbac63d3634019c4d1ca9 (patch) | |
tree | 2776a25ee6f91cede1c197add7b0ee3afa8e9a7e /source/blender/depsgraph/intern | |
parent | 18c7575f93aa73f3a25290a97950d4eb6d37f94c (diff) |
Depsgraph: Avoid relations build time scene datablock expansion
Quite straightforward implementation, allows us to remove all the cherry-picking
update of specified scene/view layer/collection fields. Makes it possible to use
generic function to update scene.
The tricky part is that we need to know view layer pointer before the whole
evaluation starts. So we actually expand scene at initialization of evaluation.
context. This is still a bit of an exceptional case, but at least we still avoid
dangerous cherry-picking update.
Diffstat (limited to 'source/blender/depsgraph/intern')
5 files changed, 39 insertions, 288 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index bdc8d7cb572..a5a28ce0a8c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -322,17 +322,6 @@ ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig) return id_node->id_cow; } -ID *DepsgraphNodeBuilder::expand_cow_id(IDDepsNode *id_node) -{ - return deg_expand_copy_on_write_datablock(graph_, id_node, this, true); -} - -ID *DepsgraphNodeBuilder::expand_cow_id(ID *id_orig) -{ - IDDepsNode *id_node = add_id_node(id_orig); - return expand_cow_id(id_node); -} - /* **** Build functions for entity nodes **** */ void DepsgraphNodeBuilder::begin_build() { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index c2aa811c8e6..df94671b4c6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -89,16 +89,6 @@ struct DepsgraphNodeBuilder { return (T *)get_cow_id(&orig->id); } - /* Get fully expanded (ready for use) copy-on-write datablock for the given - * original datablock. - */ - ID *expand_cow_id(IDDepsNode *id_node); - ID *expand_cow_id(ID *id_orig); - template<typename T> - T *expand_cow_datablock(T *orig) { - return (T *)expand_cow_id(&orig->id); - } - /* For a given COW datablock get corresponding original one. */ template<typename T> T *get_orig_datablock(const T *cow) const { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 8b770ab81a1..390619aeeaa 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -77,35 +77,13 @@ void DepsgraphNodeBuilder::build_view_layer( /* Setup currently building context. */ scene_ = scene; view_layer_ = view_layer; - /* Expand Scene Cow datablock to get proper pointers to bases. */ + /* Get pointer to a CoW version of scene ID. */ Scene *scene_cow; - ViewLayer *view_layer_cow; if (DEG_depsgraph_use_copy_on_write()) { - /* NOTE: We need to create ID nodes for all objects coming from bases, - * otherwise remapping will not replace objects with their CoW versions - * for CoW bases. - */ - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - Object *object = base->object; - add_id_node(&object->id); - } - /* Create ID node for nested ID of nodetree as well, otherwise remapping - * will not work correct either. - */ - if (scene->nodetree != NULL) { - add_id_node(&scene->nodetree->id); - } - /* Make sure we've got ID node, so we can get pointer to CoW datablock. - */ - scene_cow = expand_cow_datablock(scene); - view_layer_cow = (ViewLayer *)BLI_findstring( - &scene_cow->view_layers, - view_layer->name, - offsetof(ViewLayer, name)); + scene_cow = get_cow_datablock(scene); } else { scene_cow = scene; - view_layer_cow = view_layer; } /* Scene objects. */ int select_color = 1; @@ -114,14 +92,10 @@ void DepsgraphNodeBuilder::build_view_layer( * tricks here iterating over the view layer. */ int base_index = 0; - for (Base *base_orig = (Base *)view_layer->object_bases.first, - *base_cow = (Base *)view_layer_cow->object_bases.first; - base_orig != NULL; - base_orig = base_orig->next, base_cow = base_cow->next) - { + LISTBASE_FOREACH(Base *, base, &view_layer->object_bases) { /* object itself */ - build_object(base_index, base_orig->object, linked_state); - base_orig->object->select_color = select_color++; + build_object(base_index, base->object, linked_state); + base->object->select_color = select_color++; ++base_index; } if (scene->camera != NULL) { diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 63c9aa1407a..4e70e56ae71 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -45,6 +45,7 @@ extern "C" { #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "intern/eval/deg_eval_copy_on_write.h" #include "intern/depsgraph_intern.h" #include "intern/nodes/deg_node_id.h" @@ -77,20 +78,44 @@ short DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) Scene *DEG_get_evaluated_scene(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const DEG::Depsgraph *deg_graph = + reinterpret_cast<const DEG::Depsgraph *>(graph); Scene *scene_orig = deg_graph->scene; - return reinterpret_cast<Scene *>(deg_graph->get_cow_id(&scene_orig->id)); + Scene *scene_cow = + reinterpret_cast<Scene *>(deg_graph->get_cow_id(&scene_orig->id)); + /* TODO(sergey): Shall we expand datablock here? Or is it OK to assume + * that calleer is OK with just a pointer in case scene is not up[dated + * yet? + */ + return scene_cow; } ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const DEG::Depsgraph *deg_graph = + reinterpret_cast<const DEG::Depsgraph *>(graph); Scene *scene_cow = DEG_get_evaluated_scene(graph); + /* We update copy-on-write scene in the following cases: + * - It was not expanded yet. + * - It was tagged for update of CoW component. + * This allows us to have proper view layer pointer. + */ + if (DEG_depsgraph_use_copy_on_write() && + (!DEG::deg_copy_on_write_is_expanded(&scene_cow->id) || + scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE)) + { + const DEG::IDDepsNode *id_node = + deg_graph->find_id_node(°_graph->scene->id); + DEG::deg_update_copy_on_write_datablock(deg_graph, id_node); + } + /* Do name-based lookup. */ + /* TODO(sergey): Can this be optimized? */ ViewLayer *view_layer_orig = deg_graph->view_layer; ViewLayer *view_layer_cow = (ViewLayer *)BLI_findstring(&scene_cow->view_layers, view_layer_orig->name, offsetof(ViewLayer, name)); + BLI_assert(view_layer_cow != NULL); return view_layer_cow; } 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 3c40abe6a68..1d2169f5ec4 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 @@ -311,15 +311,6 @@ BLI_INLINE bool check_datablock_expanded(const ID *id_cow) return (id_cow->name[0] != '\0'); } -/* Check whether datablock was already expanded during depsgraph - * construction. - */ -static bool check_datablock_expanded_at_construction(const ID *id_orig) -{ - const ID_Type id_type = GS(id_orig->name); - return (id_type == ID_SCE); -} - /* Those are datablocks which are not covered by dependency graph and hence * does not need any remapping or anything. * @@ -467,219 +458,6 @@ void update_special_pointers(const Depsgraph *depsgraph, } } -void update_copy_on_write_layer_collections( - ListBase *layer_collections_cow, - const ListBase *layer_collections_orig); - -void update_copy_on_write_layer_collection( - LayerCollection *layer_collection_cow, - const LayerCollection *layer_collection_orig) -{ - // Make a local copy of original layer collection, so we can start - // modifying it. - LayerCollection local = *layer_collection_orig; - // Copy all pointer data from original CoW version of layer collection. - local.next = layer_collection_cow->next; - local.prev = layer_collection_cow->prev; - local.scene_collection = layer_collection_cow->scene_collection; - local.object_bases = layer_collection_cow->object_bases; - local.overrides = layer_collection_cow->overrides; - local.layer_collections = layer_collection_cow->layer_collections; - local.properties = layer_collection_cow->properties; - local.properties_evaluated = layer_collection_cow->properties_evaluated; - // Synchronize pointer-related data. - IDP_Reset(local.properties, layer_collection_orig->properties); - // Copy synchronized version back. - *layer_collection_cow = local; - // Recurs into nested layer collections. - update_copy_on_write_layer_collections( - &layer_collection_cow->layer_collections, - &layer_collection_orig->layer_collections); -} - -void update_copy_on_write_layer_collections( - ListBase *layer_collections_cow, - const ListBase *layer_collections_orig) -{ - const LayerCollection *layer_collection_orig = - (const LayerCollection *)layer_collections_orig->first; - LayerCollection *layer_collection_cow = - (LayerCollection *)layer_collections_cow->first; - while (layer_collection_orig != NULL) { - update_copy_on_write_layer_collection(layer_collection_cow, - layer_collection_orig); - layer_collection_orig = layer_collection_orig->next; - layer_collection_cow = layer_collection_cow->next; - } -} - -void update_copy_on_write_view_layer(const Depsgraph *depsgraph, - ViewLayer *view_layer_cow, - const ViewLayer *view_layer_orig) -{ - // Update pointers to active base. - if (view_layer_orig->basact == NULL) { - view_layer_cow->basact = NULL; - } - else { - const Object *obact_orig = view_layer_orig->basact->object; - Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id); - view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow); - } - // Update base flags. - // - // TODO(sergey): We should probably check visibled/selectabled. - // flag here? - const Base *base_orig = (Base *)view_layer_orig->object_bases.first; - Base *base_cow = (Base *)view_layer_cow->object_bases.first;; - while (base_orig != NULL) { - base_cow->flag = base_orig->flag; - base_orig = base_orig->next; - base_cow = base_cow->next; - } - // Synchronize settings. - view_layer_cow->active_collection = view_layer_orig->active_collection; - view_layer_cow->flag = view_layer_orig->flag; - view_layer_cow->layflag = view_layer_orig->layflag; - view_layer_cow->passflag = view_layer_orig->passflag; - view_layer_cow->pass_alpha_threshold = view_layer_orig->pass_alpha_threshold; - // Synchronize ID properties. - IDP_Reset(view_layer_cow->properties, view_layer_orig->properties); - IDP_Reset(view_layer_cow->id_properties, view_layer_orig->id_properties); - // Synchronize layer collections. - update_copy_on_write_layer_collections( - &view_layer_cow->layer_collections, - &view_layer_orig->layer_collections); -} - -void update_copy_on_write_view_layers(const Depsgraph *depsgraph, - Scene *scene_cow, - const Scene *scene_orig) -{ - const ViewLayer *view_layer_orig = (const ViewLayer *)scene_orig->view_layers.first; - ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first; - while (view_layer_orig != NULL) { - update_copy_on_write_view_layer(depsgraph, - view_layer_cow, - view_layer_orig); - view_layer_orig = view_layer_orig->next; - view_layer_cow = view_layer_cow->next; - } -} - -void update_copy_on_write_scene_collections( - ListBase *collections_cow, - const ListBase *collections_orig); - -void update_copy_on_write_scene_collection( - SceneCollection *collection_cow, - const SceneCollection *collection_orig) -{ - collection_cow->active_object_index = collection_orig->active_object_index; - update_copy_on_write_scene_collections( - &collection_cow->scene_collections, - &collection_orig->scene_collections); -} - -void update_copy_on_write_scene_collections( - ListBase *collections_cow, - const ListBase *collections_orig) -{ - const SceneCollection *nested_collection_orig = - (const SceneCollection *)collections_orig->first; - SceneCollection *nested_collection_cow = - (SceneCollection *)collections_cow->first; - while (nested_collection_orig != NULL) { - update_copy_on_write_scene_collection( - nested_collection_cow, - nested_collection_orig); - nested_collection_orig = nested_collection_orig->next; - nested_collection_cow = nested_collection_cow->next; - } -} - -/* Update copy-on-write version of scene from original scene. */ -void update_copy_on_write_scene(const Depsgraph *depsgraph, - Scene *scene_cow, - const Scene *scene_orig) -{ - // Some non-pointer data sync, current frame for now. - // TODO(sergey): Are we missing something here? - scene_cow->r.cfra = scene_orig->r.cfra; - scene_cow->r.subframe = scene_orig->r.subframe; - // Update view layers and collections. - update_copy_on_write_view_layers(depsgraph, scene_cow, scene_orig); - update_copy_on_write_scene_collection(scene_cow->collection, - scene_orig->collection); - /* Synchronize active render engine. */ - BLI_strncpy(scene_cow->view_render.engine_id, - scene_orig->view_render.engine_id, - sizeof(scene_cow->view_render.engine_id)); - BKE_toolsettings_free(scene_cow->toolsettings); - scene_cow->toolsettings = BKE_toolsettings_copy(scene_orig->toolsettings, 0); - /* TODO(sergey): What else do we need here? */ -} - -/* Update copy-on-write version of armature object from original scene. */ -void update_copy_on_write_object(const Depsgraph * /*depsgraph*/, - Object *object_cow, - const Object *object_orig) -{ - /* TODO(sergey): This function might be split into a smaller ones, - * reused for different updates. And maybe even moved to BKE. - */ - /* Update armature/pose related flags. */ - bPose *pose_cow = object_cow->pose; - const bPose *pose_orig = object_orig->pose; - extract_pose_from_pose(pose_cow, pose_orig); - /* Update object itself. */ - BKE_object_transform_copy(object_cow, object_orig); - object_cow->mode = object_orig->mode; -} - -/* Update copy-on-write version of datablock from it's original ID without re-building - * the whole datablock from scratch. - * - * Used for such special cases as scene collections and armatures, which can not use full - * re-alloc due to pointers used as function bindings. - */ -void update_copy_on_write_datablock(const Depsgraph *depsgraph, - const ID *id_orig, ID *id_cow) -{ - bool ok = false; - const ID_Type id_type = GS(id_orig->name); - switch (id_type) { - case ID_SCE: { - const Scene *scene_orig = (const Scene *)id_orig; - Scene *scene_cow = (Scene *)id_cow; - update_copy_on_write_scene(depsgraph, scene_cow, scene_orig); - ok = true; - break; - } - case ID_OB: { - const Object *object_orig = (const Object *)id_orig; - Object *object_cow = (Object *)id_cow; - if (object_orig->type == OB_ARMATURE) { - update_copy_on_write_object(depsgraph, - object_cow, - object_orig); - ok = true; - } - break; - } - case ID_AR: - /* Nothing to do currently. */ - ok = true; - break; - default: - break; - } - // TODO(sergey): Other ID types here. - if (!ok) { - BLI_assert(!"Missing update logic of expanded datablock"); - } -} - /* This callback is used to validate that all nested ID datablocks are * properly expanded. */ @@ -710,8 +488,6 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, DepsgraphNodeBuilder *node_builder, bool create_placeholders) { - BLI_assert(!create_placeholders || - check_datablock_expanded_at_construction(id_node->id_orig)); const ID *id_orig = id_node->id_orig; ID *id_cow = id_node->id_cow; /* No need to expand such datablocks, their copied ID is same as original @@ -833,15 +609,6 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, if (!deg_copy_on_write_is_needed(id_orig)) { return id_cow; } - /* Special case for datablocks which are expanded at the dependency graph - * construction time. This datablocks must never change pointers of their - * nested data since it is used for function bindings. - */ - if (check_datablock_expanded_at_construction(id_orig)) { - BLI_assert(check_datablock_expanded(id_cow) == true); - update_copy_on_write_datablock(depsgraph, id_orig, id_cow); - return id_cow; - } /* For the rest if datablock types we use simple logic: * - Free previously expanded data, if any. * - Perform full datablock copy. @@ -1019,6 +786,12 @@ void deg_evaluate_copy_on_write(const EvaluationContext * /*eval_ctx*/, const IDDepsNode *id_node) { DEBUG_PRINT("%s on %s\n", __func__, id_node->id_orig->name); + if (id_node->id_orig == &depsgraph->scene->id) { + /* NOTE: This is handled by eval_ctx setup routines, which + * ensures scene and view layer pointers are valid. + */ + return; + } deg_update_copy_on_write_datablock(depsgraph, id_node); } |