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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2014-01-09 17:13:26 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2014-01-13 13:57:51 +0400
commite618d8238e0e065bdfd2d9332ba7231e870a7e7d (patch)
tree4e17fe3e2aa16ba0bdd92c98ec5f206efac358f1 /source/blender/blenkernel/intern/scene.c
parentac077f016d3667a3b15853ac79b272cb0b6fd661 (diff)
Fix T38054: High CPU usage with many objects
This is a regression since threaded dependency graph landed to master. Root of the issue goes to the loads of graph preparation being done even if there's nothing to be updated. The idea of this change is to use ID type recalc bits to determine whether there're objects to be updated. Generally speaking, we now check object and object data datablocks with DAG_id_type_tagged() and if there's no such IDs tagged we skip the whole task pool creation and so, The only difficult aspect was that in some circumstances it was possible that there are tagged objects but nothing in ID recalc bit fields. There were several different circumstances when it was possible: * When one assigns object->recalc flag directly DAG flush didn't set corresponding bits to ID recalc bits. Partially it is fixed by making it so flush will set bitfield, but also for object types there's no reason to assign recalc flag directly. Using generic DAG_id_type_tag works almost the same fast as direct assignment, ensures all the bitflags are set properly and for the long run it seems it's what we would actually want to. * DAG_on_visible_update() didn't set recalc bits at all. * Some areas were checking for object->recalc != 0, however it is was possible that object recalc flag contains PSYS_RECALC_CHILD which was never cleaned from there. No idea why would we need to assign such a flag when enabling scene simplification, this is to be investigated separately. * It is possible that scene_update_post and frame_update_post handlers will modify objects. The issue is that DAG_ids_clear_recalc is called just after callbacks, which leaves objects with recalc flags but no corresponding bit in ID recalc bitfield. This leads to some kind of regression when using ID type tag fields to check whether there objects to be updated internally comparing threaded DAG with legacy one. For now let's have a workaround which will preserve tag for ID_OB if there're objects with OB_RECALC_ALL bits. This keeps behavior unchanged comparing with 2.69 release.
Diffstat (limited to 'source/blender/blenkernel/intern/scene.c')
-rw-r--r--source/blender/blenkernel/intern/scene.c72
1 files changed, 67 insertions, 5 deletions
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index e489759e312..4d8075e9cba 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1365,18 +1365,80 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
#endif
}
-static void scene_update_objects(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
+static bool scene_need_update_objects(Main *bmain)
+{
+ return
+ /* Object datablocks themselves (for OB_RECALC_OB) */
+ DAG_id_type_tagged(bmain, ID_OB) ||
+
+ /* Objects data datablocks (for OB_RECALC_DATA) */
+ DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */
+ DAG_id_type_tagged(bmain, ID_CU) || /* Curve */
+ DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */
+ DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */
+ DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */
+ DAG_id_type_tagged(bmain, ID_CA) || /* Camera */
+ DAG_id_type_tagged(bmain, ID_KE) || /* KE */
+ DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */
+ DAG_id_type_tagged(bmain, ID_AR); /* Armature */
+}
+
+static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
{
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
ThreadedObjectUpdateState state;
+ /* Early check for whether we need to invoke all the task-based
+ * tihngs (spawn new ppol, traverse dependency graph and so on).
+ *
+ * Basically if there's no ID datablocks tagged for update which
+ * corresponds to object->recalc flags (which are checked in
+ * BKE_object_handle_update() then we do nothing here.
+ */
+ if (!scene_need_update_objects(bmain)) {
+ /* For debug builds we check whether early return didn't give
+ * us any regressions in terms of missing updates.
+ *
+ * TODO(sergey): Remove once we're sure the check above is correct.
+ */
+#ifndef NDEBUG
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ Object *object = base->object;
+
+ BLI_assert((object->recalc & OB_RECALC_ALL) == 0);
+
+ if (object->proxy) {
+ BLI_assert((object->proxy->recalc & OB_RECALC_ALL) == 0);
+ }
+
+ if (object->dup_group && (object->transflag & OB_DUPLIGROUP)) {
+ GroupObject *go;
+ for (go = object->dup_group->gobject.first; go; go = go->next) {
+ if (go->ob) {
+ BLI_assert((go->ob->recalc & OB_RECALC_ALL) == 0);
+ }
+ }
+ }
+ }
+#endif
+
+ return;
+ }
+
state.eval_ctx = eval_ctx;
state.scene = scene;
state.scene_parent = scene_parent;
- memset(state.statistics, 0, sizeof(state.statistics));
- state.has_updated_objects = false;
- state.base_time = PIL_check_seconds_timer();
+
+ /* Those are only needed when blender is run with --debug argument. */
+ if (G.debug & G_DEBUG) {
+ memset(state.statistics, 0, sizeof(state.statistics));
+ state.has_updated_objects = false;
+ state.base_time = PIL_check_seconds_timer();
+ }
+
#ifdef MBALL_SINGLETHREAD_HACK
state.has_mballs = false;
#endif
@@ -1408,7 +1470,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent);
/* scene objects */
- scene_update_objects(eval_ctx, scene, scene_parent);
+ scene_update_objects(eval_ctx, bmain, scene, scene_parent);
/* scene drivers... */
scene_update_drivers(bmain, scene);