diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/anim.c | 60 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/blender.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 230 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/displist.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/dynamicpaint.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/group.c | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library.c | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mball.c | 33 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 33 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 290 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/sequencer.c | 22 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 17 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/smoke.c | 30 |
15 files changed, 600 insertions, 163 deletions
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 1624a02e773..779593c2f76 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -76,7 +76,8 @@ /* --------------------- */ /* forward declarations */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], +static void object_duplilist_recursive(EvaluationContext *eval_ctx, + ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag); /* ******************************************************************** */ @@ -326,11 +327,10 @@ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets) static void motionpaths_calc_update_scene(Scene *scene) { #if 1 // 'production' optimizations always on - /* rigid body simulation needs complete update to work correctly for now */ /* RB_TODO investigate if we could avoid updating everything */ if (BKE_scene_check_rigidbody_active(scene)) { - BKE_scene_update_for_newframe(G.main, scene, scene->lay); + BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); } else { /* otherwise we can optimize by restricting updates */ Base *base, *last = NULL; @@ -352,7 +352,7 @@ static void motionpaths_calc_update_scene(Scene *scene) * is animated but not attached to/updatable from objects */ for (base = scene->base.first; base; base = base->next) { /* update this object */ - BKE_object_handle_update(scene, base->object); + BKE_object_handle_update(G.main->eval_ctx, scene, base->object); /* if this is the last one we need to update, let's stop to save some time */ if (base == last) @@ -365,7 +365,7 @@ static void motionpaths_calc_update_scene(Scene *scene) * that doesn't force complete update, but for now, this is the * most accurate way! */ - BKE_scene_update_for_newframe(G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */ + BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */ #endif } @@ -745,7 +745,8 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[4][4], return dob; } -static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], +static void group_duplilist(EvaluationContext *eval_ctx, + ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { DupliObject *dob; @@ -775,7 +776,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste if (flag & DUPLILIST_DO_UPDATE) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ - BKE_group_handle_recalc_and_update(scene, ob, group); + BKE_group_handle_recalc_and_update(eval_ctx, scene, ob, group); } if (BKE_group_is_animated(group, ob)) @@ -792,15 +793,15 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || - ((G.is_rendering == FALSE) && dob->ob->restrictflag & OB_RESTRICT_VIEW) || - ((G.is_rendering == TRUE) && dob->ob->restrictflag & OB_RESTRICT_RENDER)) + ((eval_ctx->for_render == false) && dob->ob->restrictflag & OB_RESTRICT_VIEW) || + ((eval_ctx->for_render == true) && dob->ob->restrictflag & OB_RESTRICT_RENDER)) { dob->no_draw = TRUE; } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob_obmat_ofs, persistent_id, level + 1, id, flag); + object_duplilist_recursive(eval_ctx, &group->id, scene, go->ob, lb, ob_obmat_ofs, persistent_id, level + 1, id, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } @@ -877,6 +878,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int persist } typedef struct VertexDupliData { + EvaluationContext *eval_ctx; ID *id; /* scene or group, for recursive loops */ int level; short flag; @@ -935,7 +937,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->persistent_id, vdd->level + 1, index, vdd->flag); + object_duplilist_recursive(vdd->eval_ctx, (ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->persistent_id, vdd->level + 1, index, vdd->flag); copy_m4_m4(vdd->ob->obmat, tmpmat); } } @@ -1071,7 +1073,8 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], +static void face_duplilist(EvaluationContext *eval_ctx, + ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *ob_iter; @@ -1237,7 +1240,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, persistent_id, level + 1, a, flag); + object_duplilist_recursive(eval_ctx, (ID *)id, scene, ob, lb, ob->obmat, persistent_id, level + 1, a, flag); copy_m4_m4(ob->obmat, tmpmat); } } @@ -1254,7 +1257,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], +static void new_particle_duplilist(EvaluationContext *eval_ctx, + ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], ParticleSystem *psys, int level, short flag) { @@ -1289,7 +1293,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (!psys_check_enabled(par, psys)) return; - if (G.is_rendering == FALSE) + if (eval_ctx->for_render == false) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ @@ -1341,7 +1345,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { if (flag & DUPLILIST_DO_UPDATE) { - BKE_group_handle_recalc_and_update(scene, par, part->dup_group); + BKE_group_handle_recalc_and_update(eval_ctx, scene, par, part->dup_group); } if (part->draw & PART_DRAW_COUNT_GR) { @@ -1650,14 +1654,15 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int persiste /* ------------- */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], +static void object_duplilist_recursive(EvaluationContext *eval_ctx, + ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag) { if ((ob->transflag & OB_DUPLI) == 0) return; /* Should the dupli's be generated for this object? - Respect restrict flags */ - if (G.is_rendering) { + if (eval_ctx->for_render) { if (ob->restrictflag & OB_RESTRICT_RENDER) { return; } @@ -1679,7 +1684,7 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas /* particle system take up one level in id, the particles another */ for (; psys; psys = psys->next, psysid++) { persistent_id[level] = psysid; - new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, persistent_id, psys, level + 2, flag); + new_particle_duplilist(eval_ctx, duplilist, id, scene, ob, par_space_mat, persistent_id, psys, level + 2, flag); } persistent_id[level] = 0; @@ -1696,7 +1701,7 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas } else if (ob->transflag & OB_DUPLIFACES) { if (ob->type == OB_MESH) - face_duplilist(duplilist, id, scene, ob, par_space_mat, persistent_id, level + 1, flag); + face_duplilist(eval_ctx, duplilist, id, scene, ob, par_space_mat, persistent_id, level + 1, flag); } else if (ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ @@ -1706,7 +1711,7 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas else if (ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, scene, ob, persistent_id, level + 1, flag); /* now recursive */ + group_duplilist(eval_ctx, duplilist, scene, ob, persistent_id, level + 1, flag); /* now recursive */ if (level == 0) { for (dob = duplilist->first; dob; dob = dob->next) @@ -1722,31 +1727,30 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas /* Returns a list of DupliObject * note; group dupli's already set transform matrix. see note in group_duplilist() */ -ListBase *object_duplilist_ex(Scene *sce, Object *ob, bool update, bool for_render) +ListBase *object_duplilist_ex(EvaluationContext *eval_ctx, Scene *sce, Object *ob, bool update) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); int persistent_id[MAX_DUPLI_RECUR] = {0}; int flag = 0; /* don't allow BKE_object_handle_update for viewport during render, can crash */ - if (update && !(G.is_rendering && !for_render)) + if (update && !(G.is_rendering && !eval_ctx->for_render)) flag |= DUPLILIST_DO_UPDATE; - if (for_render) + if (eval_ctx->for_render) flag |= DUPLILIST_FOR_RENDER; duplilist->first = duplilist->last = NULL; - object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, persistent_id, 0, 0, flag); + object_duplilist_recursive(eval_ctx, (ID *)sce, sce, ob, duplilist, NULL, persistent_id, 0, 0, flag); return duplilist; } /* note: previously updating was always done, this is why it defaults to be on * but there are likely places it can be called without updating */ -ListBase *object_duplilist(Scene *sce, Object *ob, bool for_render) +ListBase *object_duplilist(EvaluationContext *eval_ctx, Scene *sce, Object *ob) { - return object_duplilist_ex(sce, ob, true, for_render); + return object_duplilist_ex(eval_ctx, sce, ob, true); } - void free_object_duplilist(ListBase *lb) { DupliObject *dob; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 96adadebb48..5b40e3ae68e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -120,6 +120,7 @@ void free_blender(void) IMB_exit(); BKE_images_exit(); + DAG_exit(); BKE_brush_system_exit(); @@ -137,7 +138,7 @@ void initglobals(void) U.savetime = 1; - G.main = MEM_callocN(sizeof(Main), "initglobals"); + G.main = BKE_main_new(); strcpy(G.ima, "//"); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 0dbb739e6f8..50e74dfba44 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -166,7 +166,7 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda unit_m4(cob->startmat); break; } - + return cob; } @@ -3351,7 +3351,8 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra float co[3] = {0.0f, 0.0f, 0.0f}; SpaceTransform transform; - DerivedMesh *target = object_get_derived_final(ct->tar); + /* TODO(sergey): use proper for_render flag here when known. */ + DerivedMesh *target = object_get_derived_final(ct->tar, false); BVHTreeFromMesh treeData = {NULL}; @@ -4014,7 +4015,8 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (data->depth_ob) { Object *depth_ob = data->depth_ob; - DerivedMesh *target = object_get_derived_final(depth_ob); + /* TODO(sergey): use proper for_render flag here when known. */ + DerivedMesh *target = object_get_derived_final(depth_ob, false); if (target) { BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeRayHit hit; diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 6ef20ecc047..8074d6bceec 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BLI_listbase.h" #include "BLI_ghash.h" +#include "BLI_threads.h" #include "DNA_anim_types.h" #include "DNA_camera_types.h" @@ -78,8 +79,22 @@ #include "BKE_screen.h" #include "BKE_tracking.h" +#include "atomic_ops.h" + #include "depsgraph_private.h" - + +static SpinLock threaded_update_lock; + +void DAG_init(void) +{ + BLI_spin_init(&threaded_update_lock); +} + +void DAG_exit(void) +{ + BLI_spin_end(&threaded_update_lock); +} + /* Queue and stack operations for dag traversal * * the queue store a list of freenodes to avoid successive alloc/dealloc @@ -418,22 +433,47 @@ static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *l la->id.flag &= ~LIB_DOIT; } +static void check_and_create_collision_relation(DagForest *dag, Object *ob, DagNode *node, Object *ob1, int skip_forcefield, bool no_collision) +{ + DagNode *node2; + if (ob1->pd && (ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) { + if ((skip_forcefield && ob1->pd->forcefield == skip_forcefield) || (no_collision && ob1->pd->forcefield == 0)) + return; + node2 = dag_get_node(dag, ob1); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision"); + } +} + static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield, bool no_collision) { Base *base; - DagNode *node2; + ParticleSystem *particle_system; + + for (particle_system = ob->particlesystem.first; + particle_system; + particle_system = particle_system->next) + { + EffectorWeights *effector_weights = particle_system->part->effector_weights; + if (effector_weights->group) { + GroupObject *group_object; + + for (group_object = effector_weights->group->gobject.first; + group_object; + group_object = group_object->next) + { + if ((group_object->ob->lay & ob->lay)) { + check_and_create_collision_relation(dag, ob, node, group_object->ob, skip_forcefield, no_collision); + } + } + } + } /* would be nice to have a list of colliders here * so for now walk all objects in scene check 'same layer rule' */ for (base = scene->base.first; base; base = base->next) { - if ((base->lay & ob->lay) && base->object->pd) { + if ((base->lay & ob->lay)) { Object *ob1 = base->object; - if ((ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) { - if ((skip_forcefield && ob1->pd->forcefield == skip_forcefield) || (no_collision && ob1->pd->forcefield == 0)) - continue; - node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision"); - } + check_and_create_collision_relation(dag, ob, node, ob1, skip_forcefield, no_collision); } } } @@ -2680,6 +2720,81 @@ void DAG_pose_sort(Object *ob) ugly_hack_sorry = 1; } +/* ************************ DAG FOR THREADED UPDATE ********************* */ + +/* Initialize run-time data in the graph needed for traversing it + * from multiple threads and start threaded tree traversal by adding + * the root node to the queue. + * + * This will mark DAG nodes as object/non-object and will calculate + * num_pending_parents of nodes (which is how many non-updated parents node + * have, which helps a lot checking whether node could be scheduled + * already or not). + */ +void DAG_threaded_update_begin(Scene *scene, + void (*func)(void *node, void *user_data), + void *user_data) +{ + DagNode *node, *root_node; + + /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */ + for (node = scene->theDag->DagNode.first; node; node = node->next) { + node->num_pending_parents = 0; + node->scheduled = false; + } + + /* ... and then iterate over all the nodes and + * increase num_pending_parents for node childs. + */ + for (node = scene->theDag->DagNode.first; node; node = node->next) { + DagAdjList *itA; + + for (itA = node->child; itA; itA = itA->next) { + if (itA->node != node) { + itA->node->num_pending_parents++; + } + } + } + + /* Add root node to the queue. */ + root_node = scene->theDag->DagNode.first; + root_node->scheduled = true; + func(root_node, user_data); +} + +/* This function is called when handling node is done. + * + * This function updates num_pending_parents for all childs and + * schedules them if they're ready. + */ +void DAG_threaded_update_handle_node_updated(void *node_v, + void (*func)(void *node, void *user_data), + void *user_data) +{ + DagNode *node = node_v; + DagAdjList *itA; + + for (itA = node->child; itA; itA = itA->next) { + DagNode *child_node = itA->node; + if (child_node != node) { + atomic_sub_uint32(&child_node->num_pending_parents, 1); + + if (child_node->num_pending_parents == 0) { + bool need_schedule; + + BLI_spin_lock(&threaded_update_lock); + need_schedule = child_node->scheduled == false; + child_node->scheduled = true; + BLI_spin_unlock(&threaded_update_lock); + + if (need_schedule) { + func(child_node, user_data); + } + } + } + } +} + /* ************************ DAG DEBUGGING ********************* */ void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob) @@ -2699,3 +2814,100 @@ void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob) dag_print_dependencies = 0; } +/* ************************ DAG tagging and querying ********************* */ + +void DAG_tag_clear_nodes(Scene *scene) +{ + DagNode *node; + + for (node = scene->theDag->DagNode.first; node; node = node->next) { + node->tag = false; + } +} + +void DAG_tag_node_for_object(Scene *scene, void *object) +{ + DagNode *node = dag_get_node(scene->theDag, object); + + node->tag = true; +} + +void DAG_tag_flush_nodes(Scene *scene) +{ + DagNodeQueue *node_queue; + DagNode *node, *root_node; + + node_queue = queue_create(DAGQUEUEALLOC); + + for (node = scene->theDag->DagNode.first; node; node = node->next) { + node->color = DAG_WHITE; + } + + root_node = scene->theDag->DagNode.first; + root_node->color = DAG_GRAY; + push_stack(node_queue, root_node); + + while (node_queue->count) { + DagAdjList *itA; + bool has_new_nodes = false; + + node = get_top_node_queue(node_queue); + + /* Schedule all child nodes. */ + for (itA = node->child; itA; itA = itA->next) { + if (itA->node->color == DAG_WHITE) { + itA->node->color = DAG_GRAY; + push_stack(node_queue, itA->node); + has_new_nodes = true; + } + } + + if (!has_new_nodes) { + node = pop_queue(node_queue); + if (node->ob == scene) { + break; + } + + /* Flush tag from child to current node. */ + for (itA = node->child; itA; itA = itA->next) { + if (itA->node->tag) { + node->tag = true; + break; + } + } + + node->color = DAG_BLACK; + } + } + + queue_delete(node_queue); +} + +/* Will return Object ID if node represents Object, + * and will return NULL otherwise. + */ +Object *DAG_get_node_object(void *node_v) +{ + DagNode *node = node_v; + + if (node->type == ID_OB) { + return node->ob; + } + + return NULL; +} + +/* Returns node name, used for debug output only, atm. */ +const char *DAG_get_node_name(void *node_v) +{ + DagNode *node = node_v; + + return dag_node_name(node); +} + +bool DAG_get_node_tag(void *node_v) +{ + DagNode *node = node_v; + + return node->tag; +} diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 1abb738608e..7ad8e80665e 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -49,9 +49,11 @@ #include "BLI_utildefines.h" #include "BKE_global.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_cdderivedmesh.h" #include "BKE_object.h" +#include "BKE_main.h" #include "BKE_mball.h" #include "BKE_material.h" #include "BKE_curve.h" @@ -709,7 +711,7 @@ float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) return displist_calc_taper(scene, taperobj, fac); } -void BKE_displist_make_mball(Scene *scene, Object *ob) +void BKE_displist_make_mball(EvaluationContext *eval_ctx, Scene *scene, Object *ob) { if (!ob || ob->type != OB_MBALL) return; @@ -723,7 +725,7 @@ void BKE_displist_make_mball(Scene *scene, Object *ob) if (ob->type == OB_MBALL) { if (ob == BKE_mball_basis_find(scene, ob)) { - BKE_mball_polygonize(scene, ob, &ob->curve_cache->disp, false); + BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp); BKE_mball_texspace_calc(ob); object_deform_mball(ob, &ob->curve_cache->disp); @@ -733,9 +735,9 @@ void BKE_displist_make_mball(Scene *scene, Object *ob) } } -void BKE_displist_make_mball_forRender(Scene *scene, Object *ob, ListBase *dispbase) +void BKE_displist_make_mball_forRender(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) { - BKE_mball_polygonize(scene, ob, dispbase, true); + BKE_mball_polygonize(eval_ctx, scene, ob, dispbase); BKE_mball_texspace_calc(ob); object_deform_mball(ob, dispbase); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e2b752ea352..5941e8b5703 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -560,7 +560,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent /* ignore cache clear during subframe updates * to not mess up cache validity */ object_cacheIgnoreClear(ob, 1); - BKE_object_handle_update(scene, ob); + BKE_object_handle_update(G.main->eval_ctx, scene, ob); object_cacheIgnoreClear(ob, 0); } else diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index a5cbf064bc2..06e63e9b754 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -47,6 +47,7 @@ #include "BLI_utildefines.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" #include "BKE_library.h" @@ -334,7 +335,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode) * you can draw everything, leaves tags in objects to signal it needs further updating */ /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void BKE_group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group) +void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group) { GroupObject *go; @@ -356,7 +357,7 @@ void BKE_group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Gr go->ob->recalc = go->recalc; group_replaces_nla(parent, go->ob, 's'); - BKE_object_handle_update(scene, go->ob); + BKE_object_handle_update(eval_ctx, scene, go->ob); group_replaces_nla(parent, go->ob, 'e'); /* leave recalc tags in case group members are in normal scene */ @@ -374,7 +375,7 @@ void BKE_group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Gr for (go = group->gobject.first; go; go = go->next) { if (go->ob) { if (go->ob->recalc) { - BKE_object_handle_update(scene, go->ob); + BKE_object_handle_update(eval_ctx, scene, go->ob); } } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 910ab0ffe1b..43bd6a0b36c 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -82,6 +82,7 @@ #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_font.h" #include "BKE_global.h" @@ -1009,6 +1010,12 @@ void BKE_libblock_free_us(ListBase *lb, void *idv) /* test users */ } } +Main *BKE_main_new(void) +{ + Main *bmain = MEM_callocN(sizeof(Main), "new main"); + bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "EvaluationCintext"); + return bmain; +} void free_main(Main *mainvar) { @@ -1069,6 +1076,7 @@ void free_main(Main *mainvar) } } + MEM_freeN(mainvar->eval_ctx); MEM_freeN(mainvar); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 1128c3e55c7..603eb50122f 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -57,6 +57,7 @@ /* #include "BKE_object.h" */ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_library.h" #include "BKE_displist.h" @@ -485,14 +486,15 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; SceneBaseIter iter; + EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) return; - while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -530,14 +532,15 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis) int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; SceneBaseIter iter; + EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) return NULL; - while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != bob) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -1637,7 +1640,7 @@ static void polygonize(PROCESS *process, MetaBall *mb) } } -static float init_meta(PROCESS *process, Scene *scene, Object *ob) /* return totsize */ +static float init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) /* return totsize */ { Scene *sce_iter = scene; Base *base; @@ -1657,8 +1660,8 @@ static float init_meta(PROCESS *process, Scene *scene, Object *ob) /* return BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* make main array */ - BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &bob)) { + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); + while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { if (bob->type == OB_MBALL) { zero_size = 0; @@ -2211,7 +2214,7 @@ static void init_metaball_octal_tree(PROCESS *process, int depth) subdivide_metaball_octal_node(node, size[0], size[1], size[2], process->metaball_tree->depth); } -static void mball_count(PROCESS *process, Scene *scene, Object *basis) +static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *basis) { Scene *sce_iter = scene; Base *base; @@ -2225,10 +2228,10 @@ static void mball_count(PROCESS *process, Scene *scene, Object *basis) process->totelem = 0; /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) return; - while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob == bob) { MetaBall *mb = ob->data; @@ -2264,7 +2267,7 @@ static void mball_count(PROCESS *process, Scene *scene, Object *basis) } } -void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for_render) +void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) { MetaBall *mb; DispList *dl; @@ -2274,10 +2277,10 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for mb = ob->data; - mball_count(&process, scene, ob); + mball_count(eval_ctx, &process, scene, ob); if (process.totelem == 0) return; - if ((for_render == false) && (mb->flag == MB_UPDATE_NEVER)) return; + if ((eval_ctx->for_render == false) && (mb->flag == MB_UPDATE_NEVER)) return; if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; process.thresh = mb->thresh; @@ -2286,7 +2289,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for process.mainb = MEM_mallocN(sizeof(void *) * process.totelem, "mainb"); /* initialize all mainb (MetaElems) */ - totsize = init_meta(&process, scene, ob); + totsize = init_meta(eval_ctx, &process, scene, ob); /* if scene includes more than one MetaElem, then octal tree optimization is used */ if ((process.totelem > 1) && (process.totelem <= 64)) init_metaball_octal_tree(&process, 1); @@ -2315,7 +2318,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for } /* width is size per polygonize cube */ - if (for_render) { + if (eval_ctx->for_render) { width = mb->rendersize; } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e480f1a6bf7..c069abfaf35 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2369,7 +2369,6 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime, /* solve constraints */ if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { bConstraintOb *cob; - cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); BKE_solve_constraints(&ob->constraints, cob, ctime); BKE_constraints_clear_evalob(cob); @@ -2686,8 +2685,7 @@ bool BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_m else { ListBase *lb; DupliObject *dob; - - lb = object_duplilist(scene, ob, FALSE); + lb = object_duplilist(G.main->eval_ctx, scene, ob); for (dob = lb->first; dob; dob = dob->next) { if ((use_hidden == false) && (dob->no_draw != 0)) { /* pass */ @@ -2764,7 +2762,7 @@ void BKE_scene_foreach_display_point( ListBase *lb; DupliObject *dob; - lb = object_duplilist(scene, ob, FALSE); + lb = object_duplilist(G.main->eval_ctx, scene, ob); for (dob = lb->first; dob; dob = dob->next) { if (dob->no_draw == 0) { BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data); @@ -2852,7 +2850,8 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob) /* the main object update call, for object matrix, constraints, keys and displist (modifiers) */ /* requires flags to be set! */ /* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */ -void BKE_object_handle_update_ex(Scene *scene, Object *ob, +void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, + Scene *scene, Object *ob, RigidBodyWorld *rbw) { if (ob->recalc & OB_RECALC_ALL) { @@ -2922,17 +2921,6 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, switch (ob->type) { case OB_MESH: { -#if 0 // XXX, comment for 2.56a release, background wont set 'scene->customdata_mask' - BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; - BLI_assert((scene->customdata_mask & CD_MASK_BAREMESH) == CD_MASK_BAREMESH); - if (em) { - makeDerivedMesh(scene, ob, em, scene->customdata_mask, 0); /* was CD_MASK_BAREMESH */ - } - else { - makeDerivedMesh(scene, ob, NULL, scene->customdata_mask, 0); - } - -#else /* ensure CD_MASK_BAREMESH for now */ BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; if (em) { @@ -2941,7 +2929,6 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, else { makeDerivedMesh(scene, ob, NULL, data_mask, 0); } -#endif break; } case OB_ARMATURE: @@ -2957,7 +2944,7 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, break; case OB_MBALL: - BKE_displist_make_mball(scene, ob); + BKE_displist_make_mball(eval_ctx, scene, ob); break; case OB_CURVE: @@ -3001,7 +2988,7 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, while (psys) { if (psys_check_enabled(ob, psys)) { /* check use of dupli objects here */ - if (psys->part && (psys->part->draw_as == PART_DRAW_REND || G.is_rendering) && + if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->for_render) && ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) { @@ -3021,7 +3008,7 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, psys = psys->next; } - if (G.is_rendering && ob->transflag & OB_DUPLIPARTS) { + if (eval_ctx->for_render && ob->transflag & OB_DUPLIPARTS) { /* this is to make sure we get render level duplis in groups: * the derivedmesh must be created before init_render_mesh, * since object_duplilist does dupliparticles before that */ @@ -3048,7 +3035,7 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, /* the no-group proxy case, we call update */ if (ob->proxy_group == NULL) { // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - BKE_object_handle_update(scene, ob->proxy); + BKE_object_handle_update(eval_ctx, scene, ob->proxy); } } } @@ -3057,9 +3044,9 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world */ -void BKE_object_handle_update(Scene *scene, Object *ob) +void BKE_object_handle_update(EvaluationContext *eval_ctx, Scene *scene, Object *ob) { - BKE_object_handle_update_ex(scene, ob, NULL); + BKE_object_handle_update_ex(eval_ctx, scene, ob, NULL); } void BKE_object_sculpt_modifiers_changed(Object *ob) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index d2ef59b238f..7b3539db287 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1408,9 +1408,8 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) { ListBase *lb_dupli_ob; - /* don't update the dupli groups, we only want their pid's */ - if ((lb_dupli_ob = object_duplilist_ex(scene, ob, FALSE, FALSE))) { + if ((lb_dupli_ob = object_duplilist_ex(G.main->eval_ctx, scene, ob, FALSE))) { DupliObject *dob; for (dob= lb_dupli_ob->first; dob; dob= dob->next) { if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */ @@ -3159,7 +3158,7 @@ static void *ptcache_bake_thread(void *ptr) efra = data->endframe; for (; (*data->cfra_ptr <= data->endframe) && !data->break_operation; *data->cfra_ptr+=data->step) { - BKE_scene_update_for_newframe(data->main, data->scene, data->scene->lay); + BKE_scene_update_for_newframe(G.main->eval_ctx, data->main, data->scene, data->scene->lay); if (G.background) { printf("bake: frame %d :: %d\n", (int)*data->cfra_ptr, data->endframe); } @@ -3390,8 +3389,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker) scene->r.framelen = frameleno; CFRA = cfrao; - if (bake) /* already on cfra unless baking */ - BKE_scene_update_for_newframe(bmain, scene, scene->lay); + if (bake) { /* already on cfra unless baking */ + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); + } if (thread_data.break_operation) WM_cursor_wait(0); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 80fcee18513..a82bbb7ca37 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -58,6 +58,7 @@ #include "BLI_callbacks.h" #include "BLI_string.h" #include "BLI_threads.h" +#include "BLI_task.h" #include "BLF_translation.h" @@ -87,6 +88,8 @@ #include "RE_engine.h" +#include "PIL_time.h" + #include "IMB_colormanagement.h" //XXX #include "BIF_previewrender.h" @@ -736,9 +739,9 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) /* used by metaballs * doesn't return the original duplicated object, only dupli's */ -int BKE_scene_base_iter_next(SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) +int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, + Scene **scene, int val, Base **base, Object **ob) { - static int in_next_object = 0; int run_again = 1; /* init */ @@ -746,18 +749,8 @@ int BKE_scene_base_iter_next(SceneBaseIter *iter, Scene **scene, int val, Base * iter->fase = F_START; iter->dupob = NULL; iter->duplilist = NULL; - - /* XXX particle systems with metas+dupligroups call this recursively */ - /* see bug #18725 */ - if (in_next_object) { - printf("ERROR: Metaball generation called recursively, not supported\n"); - - return F_ERROR; - } } else { - in_next_object = 1; - /* run_again is set when a duplilist has been ended */ while (run_again) { run_again = 0; @@ -814,7 +807,7 @@ int BKE_scene_base_iter_next(SceneBaseIter *iter, Scene **scene, int val, Base * * this enters eternal loop because of * makeDispListMBall getting called inside of group_duplilist */ if ((*base)->object->dup_group == NULL) { - iter->duplilist = object_duplilist((*scene), (*base)->object, FALSE); + iter->duplilist = object_duplilist_ex(eval_ctx, (*scene), (*base)->object, false); iter->dupob = iter->duplilist->first; @@ -856,9 +849,6 @@ int BKE_scene_base_iter_next(SceneBaseIter *iter, Scene **scene, int val, Base * } #endif - /* reset recursion test */ - in_next_object = 0; - return iter->fase; } @@ -1128,7 +1118,7 @@ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) } /* deps hack - do extra recalcs at end */ -static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent) +static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) { Base *base; @@ -1137,7 +1127,7 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent) /* sets first, we allow per definition current scene to have * dependencies on sets, but not the other way around. */ if (scene->set) - scene_depsgraph_hack(scene->set, scene_parent); + scene_depsgraph_hack(eval_ctx, scene->set, scene_parent); for (base = scene->base.first; base; base = base->next) { Object *ob = base->object; @@ -1152,7 +1142,7 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent) recalc |= OB_RECALC_DATA; ob->recalc |= recalc; - BKE_object_handle_update(scene_parent, ob); + BKE_object_handle_update(eval_ctx, scene_parent, ob); if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) { GroupObject *go; @@ -1161,7 +1151,7 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent) if (go->ob) go->ob->recalc |= recalc; } - BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group); + BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, ob, ob->dup_group); } } } @@ -1186,32 +1176,240 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) BKE_rigidbody_do_simulation(scene, ctime); } -static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scene_parent) +/* Used to visualize CPU threads activity during threaded object update, + * would pollute STDERR with whole bunch of timing information which then + * could be parsed and nicely visualized. + */ +#undef DETAILED_ANALYSIS_OUTPUT + +/* Mballs evaluation uses BKE_scene_base_iter_next which calls + * duplilist for all objects in the scene. This leads to conflict + * accessing and writting same data from multipl threads. + * + * Ideally Mballs shouldn't do such an iteration and use DAG + * queries instead. For the time being we've got new DAG + * let's keep it simple and update mballs in a ingle thread. + */ +#define MBALL_SINGLETHREAD_HACK + +typedef struct StatisicsEntry { + struct StatisicsEntry *next, *prev; + Object *object; + double start_time; + double duration; +} StatisicsEntry; + +typedef struct ThreadedObjectUpdateState { + /* TODO(sergey): We might want this to be per-thread object. */ + EvaluationContext *eval_ctx; + Scene *scene; + Scene *scene_parent; + double base_time; + + /* Execution statistics */ + ListBase statistics[BLENDER_MAX_THREADS]; + bool has_updated_objects; + +#ifdef MBALL_SINGLETHREAD_HACK + bool has_mballs; +#endif +} ThreadedObjectUpdateState; + +static void scene_update_object_add_task(void *node, void *user_data); + +static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) { Base *base; - - scene->customdata_mask = scene_parent->customdata_mask; - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_update_tagged_recursive(bmain, scene->set, scene_parent); - - /* scene objects */ for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - - BKE_object_handle_update_ex(scene_parent, ob, scene->rigidbody_world); - - if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) - BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group); - + Object *object = base->object; + + BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world); + + if (object->dup_group && (object->transflag & OB_DUPLIGROUP)) + BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, object, object->dup_group); + /* always update layer, so that animating layers works (joshua july 2010) */ /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */ // base->lay = ob->lay; } - +} + +static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadid) +{ +/* Disable print for now in favor of summary statistics at the end of update. */ +#define PRINT if (false) printf + + ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool); + void *node = taskdata; + Object *object = DAG_get_node_object(node); + EvaluationContext *eval_ctx = state->eval_ctx; + Scene *scene = state->scene; + Scene *scene_parent = state->scene_parent; + +#ifdef MBALL_SINGLETHREAD_HACK + if (object && object->type == OB_MBALL) { + state->has_mballs = true; + } + else +#endif + if (object) { + double start_time = 0.0; + bool add_to_stats = false; + + PRINT("Thread %d: update object %s\n", threadid, object->id.name); + + if (G.debug & G_DEBUG) { + start_time = PIL_check_seconds_timer(); + + if (object->recalc & OB_RECALC_ALL) { + state->has_updated_objects = true; + add_to_stats = true; + } + } + + /* We only update object itself here, dupli-group will be updated + * separately from main thread because of we've got no idea about + * dependnecies inside the group. + */ + BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world); + + /* Calculate statistics. */ + if (add_to_stats) { + StatisicsEntry *entry; + + entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics"); + entry->object = object; + entry->start_time = start_time; + entry->duration = PIL_check_seconds_timer() - start_time; + + BLI_addtail(&state->statistics[threadid], entry); + } + } + else { + PRINT("Threda %d: update node %s\n", threadid, + DAG_get_node_name(node)); + } + + /* Update will decrease child's valency and schedule child with zero valency. */ + DAG_threaded_update_handle_node_updated(node,scene_update_object_add_task, pool); + +#undef PRINT +} + +static void scene_update_object_add_task(void *node, void *user_data) +{ + TaskPool *task_pool = user_data; + + BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW); +} + +static void print_threads_statistics(ThreadedObjectUpdateState *state) +{ + int i, tot_thread; + + if ((G.debug & G_DEBUG) == 0) { + return; + } + +#ifdef DETAILED_ANALYSIS_OUTPUT + if (state->has_updated_objects) { + tot_thread = BLI_system_thread_count(); + + fprintf(stderr, "objects update base time %f\n", state->base_time); + + for (i = 0; i < tot_thread; i++) { + StatisicsEntry *entry; + for (entry = state->statistics[i].first; + entry; + entry = entry->next) + { + fprintf(stderr, "thread %d object %s start_time %f duration %f\n", + i, entry->object->id.name + 2, + entry->start_time, entry->duration); + } + BLI_freelistN(&state->statistics[i]); + } + } +#else + tot_thread = BLI_system_thread_count(); + + for (i = 0; i < tot_thread; i++) { + int total_objects = 0; + double total_time = 0.0; + StatisicsEntry *entry; + + if (state->has_updated_objects) { + /* Don't pollute output if no objects were updated. */ + for (entry = state->statistics[i].first; + entry; + entry = entry->next) + { + total_objects++; + total_time += entry->duration; + } + + printf("Thread %d: total %d objects in %f sec.\n", i, total_objects, total_time); + + for (entry = state->statistics[i].first; + entry; + entry = entry->next) + { + printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration); + } + } + + BLI_freelistN(&state->statistics[i]); + } +#endif +} + +static void scene_update_objects(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) +{ + TaskScheduler *task_scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + ThreadedObjectUpdateState state; + + 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(); +#ifdef MBALL_SINGLETHREAD_HACK + state.has_mballs = false; +#endif + + task_pool = BLI_task_pool_create(task_scheduler, &state); + + DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + + if (G.debug & G_DEBUG) { + print_threads_statistics(&state); + } + +#ifdef MBALL_SINGLETHREAD_HACK + if (state.has_mballs) { + scene_update_all_bases(eval_ctx, scene, scene_parent); + } +#endif +} + +static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) +{ + scene->customdata_mask = scene_parent->customdata_mask; + + /* sets first, we allow per definition current scene to have + * dependencies on sets, but not the other way around. */ + if (scene->set) + scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent); + + /* scene objects */ + scene_update_objects(eval_ctx, scene, scene_parent); + /* scene drivers... */ scene_update_drivers(bmain, scene); @@ -1223,8 +1421,7 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen } -/* this is called in main loop, doing tagged updates before redraw */ -void BKE_scene_update_tagged(Main *bmain, Scene *scene) +void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; @@ -1251,7 +1448,7 @@ void BKE_scene_update_tagged(Main *bmain, Scene *scene) * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ - scene_update_tagged_recursive(bmain, scene, scene); + scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); /* extra call here to recalc scene animation (for sequencer) */ { @@ -1271,10 +1468,13 @@ void BKE_scene_update_tagged(Main *bmain, Scene *scene) } /* applies changes right away, does all sets too */ -void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) +void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay) { float ctime = BKE_scene_frame_get(sce); Scene *sce_iter; +#ifdef DETAILED_ANALYSIS_OUTPUT + double start_time = PIL_check_seconds_timer(); +#endif /* keep this first */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); @@ -1329,9 +1529,9 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) scene_do_rb_simulation_recursive(sce, ctime); /* BKE_object_handle_update() on all objects, groups and sets */ - scene_update_tagged_recursive(bmain, sce, sce); + scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); - scene_depsgraph_hack(sce, sce); + scene_depsgraph_hack(eval_ctx, sce, sce); /* notify editors and python about recalc */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); @@ -1341,6 +1541,10 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) /* clear recalc flags */ DAG_ids_clear_recalc(bmain); + +#ifdef DETAILED_ANALYSIS_OUTPUT + fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time); +#endif } /* return default layer, also used to patch old files */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 49b237fc3ea..dd2bd4383b6 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -57,6 +57,7 @@ #include "BLF_translation.h" #include "BKE_animsys.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -498,7 +499,9 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe /*********************** sequencer pipeline functions *************************/ -SeqRenderData BKE_sequencer_new_render_data(Main *bmain, Scene *scene, int rectx, int recty, int preview_render_size) +SeqRenderData BKE_sequencer_new_render_data(EvaluationContext *eval_ctx, + Main *bmain, Scene *scene, int rectx, int recty, + int preview_render_size) { SeqRenderData rval; @@ -509,6 +512,7 @@ SeqRenderData BKE_sequencer_new_render_data(Main *bmain, Scene *scene, int rectx rval.preview_render_size = preview_render_size; rval.motion_blur_samples = 0; rval.motion_blur_shutter = 0; + rval.eval_ctx = eval_ctx; return rval; } @@ -1506,6 +1510,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho SeqRenderData render_context; Sequence *seq = context->seq; Scene *scene = context->scene; + Main *bmain = context->bmain; int cfra; if (seq->type == SEQ_TYPE_MOVIE) { @@ -1527,7 +1532,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho /* fail safe code */ - render_context = BKE_sequencer_new_render_data(context->bmain, context->scene, + render_context = BKE_sequencer_new_render_data(bmain->eval_ctx, bmain, context->scene, (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100); @@ -2449,7 +2454,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float const short is_rendering = G.is_rendering; const short is_background = G.background; - const int do_seq_gl = G.is_rendering ? + const int do_seq_gl = is_rendering ? 0 /* (context.scene->r.seq_flag & R_SEQ_GL_REND) */ : (context.scene->r.seq_flag & R_SEQ_GL_PREV); int do_seq; @@ -2505,7 +2510,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float context.scene->r.seq_prev_type = 3 /* == OB_SOLID */; /* opengl offscreen render */ - BKE_scene_update_for_newframe(context.bmain, scene, scene->lay); + BKE_scene_update_for_newframe(context.eval_ctx, context.bmain, scene, scene->lay); ibuf = sequencer_view3d_cb(scene, camera, context.rectx, context.recty, IB_rect, context.scene->r.seq_prev_type, context.scene->r.seq_flag & R_SEQ_SOLID_TEX, TRUE, scene->r.alphamode, err_out); @@ -2528,8 +2533,8 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float if (!is_thread_main || is_rendering == FALSE || is_background) { if (re == NULL) re = RE_NewRender(scene->id.name); - - BKE_scene_update_for_newframe(context.bmain, scene, scene->lay); + + BKE_scene_update_for_newframe(context.eval_ctx, context.bmain, scene, scene->lay); RE_BlenderFrame(re, context.bmain, scene, NULL, camera, scene->lay, frame, FALSE); /* restore previous state after it was toggled on & off by RE_BlenderFrame */ @@ -2564,8 +2569,9 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float scene->r.cfra = oldcfra; - if (frame != oldcfra) - BKE_scene_update_for_newframe(context.bmain, scene, scene->lay); + if (frame != oldcfra) { + BKE_scene_update_for_newframe(context.eval_ctx, context.bmain, scene, scene->lay); + } #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 3a6912157fd..6a7c16d1162 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -68,11 +68,16 @@ /* get derived mesh */ /* TODO is anyfunction that does this? returning the derivedFinal without we caring if its in edit mode or not? */ -DerivedMesh *object_get_derived_final(Object *ob) +DerivedMesh *object_get_derived_final(Object *ob, bool for_render) { Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; + if (for_render) { + /* TODO(sergey): use proper derived render here in the future. */ + return ob->derivedFinal; + } + if (em) { DerivedMesh *dm = em->derivedFinal; return dm; @@ -271,7 +276,7 @@ int BKE_shrinkwrap_project_normal(char options, const float vert[3], } -static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool forRender) { int i; @@ -319,7 +324,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) } if (calc->smd->auxTarget) { - auxMesh = object_get_derived_final(calc->smd->auxTarget); + auxMesh = object_get_derived_final(calc->smd->auxTarget, forRender); if (!auxMesh) return; SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); @@ -500,7 +505,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) /* Main shrinkwrap function */ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, bool forRender) { DerivedMesh *ss_mesh = NULL; @@ -528,7 +533,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM if (smd->target) { - calc.target = object_get_derived_final(smd->target); + calc.target = object_get_derived_final(smd->target, forRender); /* TODO there might be several "bugs" on non-uniform scales matrixs * because it will no longer be nearest surface, not sphere projection @@ -579,7 +584,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM break; case MOD_SHRINKWRAP_PROJECT: - TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project); + TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc, forRender), deform_project); break; case MOD_SHRINKWRAP_NEAREST_VERTEX: diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index bd9d20333e5..a08103d2446 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -77,7 +77,9 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" +#include "BKE_global.h" #include "BKE_effect.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -164,7 +166,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color), float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {} -struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; } +struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm), bool UNUSED(for_render)) { return NULL; } float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; } void flame_get_spectrum(unsigned char *UNUSED(spec), int UNUSED(width), float UNUSED(t1), float UNUSED(t2)) {} @@ -943,7 +945,7 @@ static void object_cacheIgnoreClear(Object *ob, int state) BLI_freelistN(&pidlist); } -static int subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int parent_recursion, float frame) +static int subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int parent_recursion, float frame, bool for_render) { SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke); bConstraint *con; @@ -956,8 +958,8 @@ static int subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int if (parent_recursion) { int recursion = parent_recursion - 1; int is_domain = 0; - if (ob->parent) is_domain += subframe_updateObject(scene, ob->parent, 0, recursion, frame); - if (ob->track) is_domain += subframe_updateObject(scene, ob->track, 0, recursion, frame); + if (ob->parent) is_domain += subframe_updateObject(scene, ob->parent, 0, recursion, frame, for_render); + if (ob->track) is_domain += subframe_updateObject(scene, ob->track, 0, recursion, frame, for_render); /* skip subframe if object is parented * to vertex of a dynamic paint canvas */ @@ -974,7 +976,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int cti->get_constraint_targets(con, &targets); for (ct = targets.first; ct; ct = ct->next) { if (ct->tar) - subframe_updateObject(scene, ct->tar, 0, recursion, frame); + subframe_updateObject(scene, ct->tar, 0, recursion, frame, for_render); } /* free temp targets */ if (cti->flush_constraint_targets) @@ -990,7 +992,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int /* ignore cache clear during subframe updates * to not mess up cache validity */ object_cacheIgnoreClear(ob, 1); - BKE_object_handle_update(scene, ob); + BKE_object_handle_update(G.main->eval_ctx, scene, ob); object_cacheIgnoreClear(ob, 0); } else @@ -2014,7 +2016,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value } } -static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) +static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt, bool for_render) { Object **flowobjs = NULL; EmissionMap *emaps = NULL; @@ -2117,7 +2119,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd } else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ /* update flow object frame */ - subframe_updateObject(scene, collob, 1, 5, BKE_scene_frame_get(scene)); + subframe_updateObject(scene, collob, 1, 5, BKE_scene_frame_get(scene), for_render); /* apply flow */ emit_from_derivedmesh(collob, sds, sfs, &em_temp, sdt); @@ -2427,7 +2429,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, pdEndEffectors(&effectors); } -static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps) +static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps, bool for_render) { SmokeDomainSettings *sds = smd->domain; /* stability values copied from wturbulence.cpp */ @@ -2497,7 +2499,7 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh * for (substep = 0; substep < totalSubsteps; substep++) { // calc animated obstacle velocities - update_flowsfluids(scene, ob, sds, dtSubdiv); + update_flowsfluids(scene, ob, sds, dtSubdiv, for_render); update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps); if (sds->total_cells > 1) { @@ -2594,7 +2596,7 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) return result; } -static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, bool for_render) { if ((smd->type & MOD_SMOKE_TYPE_FLOW)) { @@ -2716,7 +2718,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * } - step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base); + step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base, for_render); } // create shadows before writing cache so they get stored @@ -2736,13 +2738,13 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * } } -struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, bool for_render) { /* lock so preview render does not read smoke data while it gets modified */ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - smokeModifier_process(smd, scene, ob, dm); + smokeModifier_process(smd, scene, ob, dm, for_render); if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_unlock(smd->domain->fluid_mutex); |