diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 7de7a745ed6..e87fef1c864 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -32,6 +32,7 @@ * \author nzc * \since March 2001 */ +struct EvaluationContext; struct Path; struct Object; struct PartEff; @@ -65,8 +66,8 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl /* ---------------------------------------------------- */ /* Dupli-Geometry */ -struct ListBase *object_duplilist_ex(struct Scene *sce, struct Object *ob, bool update, bool for_render); -struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob, bool for_render); +struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update); +struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob); void free_object_duplilist(struct ListBase *lb); int count_duplilist(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 6baf20aeb2c..be5ae7fc353 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -48,6 +48,21 @@ struct ID; struct Main; struct Object; struct Scene; +struct ListBase; + +/* Dependency graph evaluation context + * + * This structure stores all the local dependency graph data, + * which is needed for it's evaluation, + */ +typedef struct EvaluationContext { + bool for_render; /* Set to true if evaluation shall be performed for render purposes, + keep at false if update shall happen for the viewport. */ +} EvaluationContext; + +/* Global initialization/deinitialization */ +void DAG_init(void); +void DAG_exit(void); /* Build and Update * @@ -115,10 +130,30 @@ void DAG_pose_sort(struct Object *ob); void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id), void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated)); +/* ** Threaded update ** */ + +/* Initialize the DAG for threaded update. */ +void DAG_threaded_update_begin(struct Scene *scene, + void (*func)(void *node, void *user_data), + void *user_data); + +void DAG_threaded_update_handle_node_updated(void *node_v, + void (*func)(void *node, void *user_data), + void *user_data); + /* Debugging: print dependency graph for scene or armature object to console */ void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob); +/* Tagging and querying */ +void DAG_tag_clear_nodes(struct Scene *scene); +void DAG_tag_node_for_object(struct Scene *scene, void *object); +void DAG_tag_flush_nodes(struct Scene *scene); + +struct Object *DAG_get_node_object(void *node_v); +const char *DAG_get_node_name(void *node_v); +bool DAG_get_node_tag(void *node_v); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 2178f860825..dab552069f1 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -62,6 +62,7 @@ struct Material; struct Bone; struct Mesh; struct DerivedMesh; +struct EvaluationContext; /* used for curves, nurbs, mball, importing */ typedef struct DispList { @@ -91,8 +92,8 @@ void BKE_displist_make_surf(struct Scene *scene, struct Object *ob, struct ListB void BKE_displist_make_curveTypes(struct Scene *scene, struct Object *ob, int forOrco); void BKE_displist_make_curveTypes_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **derivedFinal, int forOrco, int renderResolution); void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); -void BKE_displist_make_mball(struct Scene *scene, struct Object *ob); -void BKE_displist_make_mball_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); +void BKE_displist_make_mball(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +void BKE_displist_make_mball_forRender(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4); void BKE_displist_fill(struct ListBase *dispbase, struct ListBase *to, const float normal_proj[3], const bool flipnormal); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 0f36b7a8cfc..f528fe8c7f9 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -34,6 +34,7 @@ */ struct Base; +struct EvaluationContext; struct Group; struct GroupObject; struct Main; @@ -52,6 +53,6 @@ bool BKE_group_object_exists(struct Group *group, struct Object *ob); bool BKE_group_is_animated(struct Group *group, struct Object *parent); void BKE_group_tag_recalc(struct Group *group); -void BKE_group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group); +void BKE_group_handle_recalc_and_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *parent, struct Group *group); #endif /* __BKE_GROUP_H__ */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index f97bb911a12..cad3f264fb8 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -77,6 +77,8 @@ void BKE_libblock_free(struct ListBase *lb, void *idv); void BKE_libblock_free_ex(struct ListBase *lb, void *idv, bool do_id_user); void BKE_libblock_free_us(struct ListBase *lb, void *idv); void BKE_libblock_free_data(struct ID *id); + +struct Main *BKE_main_new(void); void free_main(struct Main *mainvar); void tag_main_idcode(struct Main *mainvar, const short type, const short tag); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 7b7b69034a9..721866daff5 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -46,6 +46,7 @@ extern "C" { #endif +struct EvaluationContext; struct Library; typedef struct Main { @@ -92,6 +93,9 @@ typedef struct Main { ListBase linestyle; char id_tag_update[256]; + + /* Evaluation context used by viewport */ + struct EvaluationContext *eval_ctx; } Main; #define MAIN_VERSION_ATLEAST(main, ver, subver) \ diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 7665e1b54dc..56ea44fa6e9 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -32,6 +32,7 @@ * \since March 2001 * \author nzc */ +struct EvaluationContext; struct Main; struct MetaBall; struct Object; @@ -47,7 +48,7 @@ void BKE_mball_make_local(struct MetaBall *mb); void BKE_mball_cubeTable_free(void); -void BKE_mball_polygonize(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, bool for_render); +void BKE_mball_polygonize(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 94995404f2b..419b8de2bc3 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -34,6 +34,7 @@ extern "C" { #endif struct Base; +struct EvaluationContext; struct Scene; struct Object; struct Camera; @@ -162,8 +163,9 @@ void BKE_object_tfm_protected_restore(struct Object *ob, const ObjectTfmProtectedChannels *obtfm, const short protectflag); -void BKE_object_handle_update(struct Scene *scene, struct Object *ob); -void BKE_object_handle_update_ex(struct Scene *scene, struct Object *ob, +void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, struct RigidBodyWorld *rbw); void BKE_object_sculpt_modifiers_changed(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 61f665be586..4ff1c8ba3a4 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -39,6 +39,7 @@ extern "C" { struct AviCodecData; struct Base; +struct EvaluationContext; struct bglMats; struct Main; struct Object; @@ -85,7 +86,8 @@ typedef struct SceneBaseIter { int fase; } SceneBaseIter; -int BKE_scene_base_iter_next(struct SceneBaseIter *iter, struct Scene **scene, int val, struct Base **base, struct Object **ob); +int BKE_scene_base_iter_next(struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter, + struct Scene **scene, int val, struct Base **base, struct Object **ob); void BKE_scene_base_flag_to_objects(struct Scene *scene); void BKE_scene_base_flag_from_objects(struct Scene *scene); @@ -111,9 +113,9 @@ float BKE_scene_frame_get(struct Scene *scene); float BKE_scene_frame_get_from_ctime(struct Scene *scene, const float frame); void BKE_scene_frame_set(struct Scene *scene, double cfra); -void BKE_scene_update_tagged(struct Main *bmain, struct Scene *sce); - -void BKE_scene_update_for_newframe(struct Main *bmain, struct Scene *sce, unsigned int lay); +/* ** Scene evaluation ** */ +void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce); +void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay); struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name); int BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 12b6d18ab7c..0ca1d904d6f 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -31,6 +31,7 @@ */ struct bContext; +struct EvaluationContext; struct StripColorBalance; struct Editing; struct ImBuf; @@ -89,6 +90,7 @@ void BKE_sequence_iterator_end(SeqIterator *iter); } typedef struct SeqRenderData { + struct EvaluationContext *eval_ctx; struct Main *bmain; struct Scene *scene; int rectx; @@ -98,8 +100,8 @@ typedef struct SeqRenderData { float motion_blur_shutter; } SeqRenderData; -SeqRenderData BKE_sequencer_new_render_data(struct Main *bmain, struct Scene *scene, int rectx, int recty, - int preview_render_size); +SeqRenderData BKE_sequencer_new_render_data(struct EvaluationContext *eval_ctx, struct Main *bmain, + struct Scene *scene, int rectx, int recty, int preview_render_size); /* Wipe effect */ enum { diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 323a926863c..6e85d9ee0a0 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -37,7 +37,7 @@ #include "BKE_customdata.h" struct DerivedMesh; struct Object; -struct DerivedMesh *object_get_derived_final(struct Object *ob); +struct DerivedMesh *object_get_derived_final(struct Object *ob, bool for_render); /* SpaceTransform stuff */ @@ -122,7 +122,7 @@ typedef struct ShrinkwrapCalcData { } ShrinkwrapCalcData; void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, - float (*vertexCos)[3], int numVerts); + float (*vertexCos)[3], int numVerts, bool forRender); /* * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h index 20366f00df6..07d156cfa02 100644 --- a/source/blender/blenkernel/BKE_smoke.h +++ b/source/blender/blenkernel/BKE_smoke.h @@ -35,7 +35,7 @@ typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); -struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm); +struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, bool for_render); void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old); void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old); diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h index c8ce2bb2a77..f4a6e4417e0 100644 --- a/source/blender/blenkernel/depsgraph_private.h +++ b/source/blender/blenkernel/depsgraph_private.h @@ -92,6 +92,14 @@ typedef struct DagNode { struct DagAdjList *child; struct DagAdjList *parent; struct DagNode *next; + + /* Threaded evaluation routines */ + uint32_t num_pending_parents; /* number of parents which are not updated yet + * this node has got. + * Used by threaded update for faster detect whether node could be + * updated aready. + */ + bool tag, scheduled; } DagNode; typedef struct DagNodeQueueElem { 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); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ac69394a309..035a917d37f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -492,7 +492,7 @@ void blo_split_main(ListBase *mainlist, Main *main) return; for (lib = main->library.first; lib; lib = lib->id.next) { - Main *libmain = MEM_callocN(sizeof(Main), "libmain"); + Main *libmain = BKE_main_new(); libmain->curlib = lib; BLI_addtail(mainlist, libmain); } @@ -545,7 +545,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab } } - m = MEM_callocN(sizeof(Main), "find_main"); + m = BKE_main_new(); BLI_addtail(mainlist, m); lib = BKE_libblock_alloc(&m->library, ID_LI, "lib"); @@ -6548,7 +6548,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) lib->packedfile = direct_link_packedfile(fd, lib->packedfile); /* new main */ - newmain= MEM_callocN(sizeof(Main), "directlink"); + newmain = BKE_main_new(); BLI_addtail(fd->mainlist, newmain); newmain->curlib = lib; @@ -7572,7 +7572,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) ListBase mainlist = {NULL, NULL}; bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata"); - bfd->main = MEM_callocN(sizeof(Main), "readfile_Main"); + bfd->main = BKE_main_new(); BLI_addtail(&mainlist, bfd->main); fd->mainlist = &mainlist; diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index c1b6dc83139..559b180189f 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -942,7 +942,7 @@ std::string AnimationExporter::create_4x4_source(std::vector &frames, Obj float ctime = BKE_scene_frame_get_from_ctime(scene, *it); CFRA = BKE_scene_frame_get_from_ctime(scene, *it); - //BKE_scene_update_for_newframe(G.main,scene,scene->lay); + //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay); BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); if (bone) { diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index ef300fa9db6..5da33663897 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -35,6 +35,8 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_editmesh.h" @@ -374,7 +376,7 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe * automatically building this data if invalid. Or something. */ // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - BKE_object_handle_update(scene, obedit); + BKE_object_handle_update(G.main->eval_ctx, scene, obedit); /* individual faces? */ if (nr == 2) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4982ce3571c..8475512cdaa 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -39,8 +39,10 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_depsgraph.h" #include "BKE_key.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_report.h" @@ -48,6 +50,7 @@ #include "BKE_editmesh_bvh.h" #include "BKE_object.h" /* XXX. only for EDBM_mesh_ensure_valid_dm_hack() which will be removed */ +#include "BKE_scene.h" /* XXX, only for eval_ctx used in EDBM_mesh_ensure_valid_dm_hack */ #include "WM_api.h" #include "WM_types.h" @@ -111,7 +114,7 @@ void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em) (em->ob->recalc & OB_RECALC_DATA)) { em->ob->recalc |= OB_RECALC_DATA; /* since we may not have done selection flushing */ - BKE_object_handle_update(scene, em->ob); + BKE_object_handle_update(G.main->eval_ctx, scene, em->ob); } } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index c67d389e5d0..669d762029a 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1234,7 +1234,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (!(base->object->transflag & OB_DUPLI)) return; - lb = object_duplilist(scene, base->object, FALSE); + lb = object_duplilist(bmain->eval_ctx, scene, base->object); if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new("make_object_duplilist_real dupli_gh"); @@ -1670,7 +1670,7 @@ static int convert_exec(bContext *C, wmOperator *op) } if (!baseob->curve_cache || !baseob->curve_cache->disp.first) { - BKE_displist_make_mball(scene, baseob); + BKE_displist_make_mball(bmain->eval_ctx, scene, baseob); } if (!(baseob->flag & OB_DONE)) { diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index c06164203b6..d3b376fe1be 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1907,7 +1907,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) BKE_lattice_modifiers_calc(scene, ob); } else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(scene, ob); + BKE_displist_make_mball(CTX_data_main(C)->eval_ctx, scene, ob); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_displist_make_curveTypes(scene, ob, 0); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index a95e36d6480..a1d09963eb7 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -149,7 +149,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender) SeqRenderData context; int chanshown = oglrender->sseq ? oglrender->sseq->chanshown : 0; - context = BKE_sequencer_new_render_data(oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f); + context = BKE_sequencer_new_render_data(oglrender->bmain->eval_ctx, oglrender->bmain, + scene, oglrender->sizex, oglrender->sizey, 100.0f); ibuf = BKE_sequencer_give_ibuf(context, CFRA, chanshown); @@ -458,7 +459,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) if (oglrender->timer) { /* exec will not have a timer */ scene->r.cfra = oglrender->cfrao; - BKE_scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender)); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender)); WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer); } @@ -531,7 +532,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) if (lay & 0xFF000000) lay &= 0xFF000000; - BKE_scene_update_for_newframe(bmain, scene, lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, lay); CFRA++; } @@ -549,7 +550,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) WM_cursor_time(oglrender->win, scene->r.cfra); - BKE_scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender)); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender)); if (view_context) { if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) { diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index e00f98c59e8..abf049ffc83 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1505,6 +1505,7 @@ void ED_screen_set(bContext *C, bScreen *sc) if (oldscreen != sc) { wmTimer *wt = oldscreen->animtimer; ScrArea *sa; + Scene *oldscene = oldscreen->scene; /* remove handlers referencing areas in old screen */ for (sa = oldscreen->areabase.first; sa; sa = sa->next) { @@ -1531,6 +1532,21 @@ void ED_screen_set(bContext *C, bScreen *sc) /* makes button hilites work */ WM_event_add_mousemove(C); + + /* Needed to make sure all the derivedMeshes are + * up-to-date before viewport starts acquiring this. + * + * This is needed in cases when, for example, boolean + * modifier uses operant from invisible layer. + * Without this trick boolean wouldn't apply correct. + * + * Quite the same happens when setting screen's scene, + * so perhaps this is in fact correct thing to do. + */ + if (oldscene != sc->scene) { + BKE_scene_set_background(bmain, sc->scene); + DAG_on_visible_update(bmain, FALSE); + } } } @@ -2016,7 +2032,7 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute)) layers |= BKE_screen_visible_layers(window->screen, scene); /* this function applies the changes too */ - BKE_scene_update_for_newframe(bmain, scene, layers); /* BKE_scene.h */ + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers); //if ( (CFRA>1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB)) // audiostream_scrub( CFRA ); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 81b0992c878..50a90d4428c 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -287,11 +287,11 @@ static int sound_bake_animation_exec(bContext *C, wmOperator *UNUSED(op)) for (cfra = (scene->r.sfra > 0) ? (scene->r.sfra - 1) : 0; cfra <= scene->r.efra + 1; cfra++) { scene->r.cfra = cfra; - BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); } scene->r.cfra = oldfra; - BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 7120a699f02..ea06e26fb5a 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -900,7 +900,7 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot) /* api callbacks */ ot->exec = image_view_zoom_ratio_exec; ot->poll = space_image_main_area_poll; - + /* properties */ RNA_def_float(ot->srna, "ratio", 0.0f, -FLT_MAX, FLT_MAX, "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 267b070fd42..c6aec21f946 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -48,8 +48,8 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_sequencer.h" - #include "BKE_sound.h" #include "IMB_colormanagement.h" @@ -838,7 +838,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int rectx = (render_size * (float)scene->r.xsch) / 100.0f + 0.5f; recty = (render_size * (float)scene->r.ysch) / 100.0f + 0.5f; - context = BKE_sequencer_new_render_data(bmain, scene, rectx, recty, proxy_size); + context = BKE_sequencer_new_render_data(bmain->eval_ctx, bmain, scene, rectx, recty, proxy_size); /* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled * by Esc pressed somewhere in the past diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index f825f7ecf9f..9eb3fb320be 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -59,6 +59,7 @@ #include "BKE_image.h" #include "BKE_key.h" #include "BKE_lattice.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -4056,7 +4057,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 if (BKE_mball_is_basis(ob)) { lb = ob->curve_cache ? &ob->curve_cache->disp : NULL; if (ELEM(NULL, lb, lb->first)) { - BKE_displist_make_mball(scene, ob); + BKE_displist_make_mball(G.main->eval_ctx, scene, ob); lb = &ob->curve_cache->disp; } if (lb->first == NULL) { @@ -6268,7 +6269,7 @@ static void draw_bounding_volume(Scene *scene, Object *ob, char type) if (BKE_mball_is_basis(ob)) { bb = ob->bb; if (bb == NULL) { - BKE_displist_make_mball(scene, ob); + BKE_displist_make_mball(G.main->eval_ctx, scene, ob); bb = ob->bb; } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 701fb26a562..f0a943d593e 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -55,6 +55,7 @@ #include "BKE_customdata.h" #include "BKE_image.h" #include "BKE_key.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_global.h" #include "BKE_paint.h" @@ -1968,7 +1969,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas if (base->object->restrictflag & OB_RESTRICT_VIEW) return; tbase.flag = OB_FROMDUPLI | base->flag; - lb = object_duplilist(scene, base->object, false); + lb = object_duplilist(G.main->eval_ctx, scene, base->object); // BLI_sortlist(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ dob = dupli_step(lb->first); @@ -2402,7 +2403,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d) if (ob->transflag & OB_DUPLI) { DupliObject *dob; - ListBase *lb = object_duplilist(scene, ob, false); + ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); for (dob = lb->first; dob; dob = dob->next) if (dob->ob->type == OB_LAMP) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index d81ab0319e6..dcbcb127f5c 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -984,7 +984,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b Base tbase; tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(scene, base->object, false); + lb = object_duplilist(G.main->eval_ctx, scene, base->object); for (dob = lb->first; dob; dob = dob->next) { tbase.object = dob->ob; @@ -1543,7 +1543,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) //XXX restore_all_scene_cfra(scene_cfra_store); BKE_scene_set_background(CTX_data_main(C), startscene); - //XXX BKE_scene_update_for_newframe(bmain, scene, scene->lay); + //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index c06ccccf88d..4bd4db9849b 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4906,8 +4906,10 @@ static void set_trans_object_base_flags(TransInfo *t) /* handle pending update events, otherwise they got copied below */ for (base = scene->base.first; base; base = base->next) { - if (base->object->recalc) - BKE_object_handle_update(t->scene, base->object); + if (base->object->recalc) { + /* TODO(sergey): Ideally, it's not needed. */ + BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object); + } } for (base = scene->base.first; base; base = base->next) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index b614ee207c6..5b90cc93083 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -55,10 +55,12 @@ #include "BIF_gl.h" #include "BKE_DerivedMesh.h" +#include "BKE_global.h" #include "BKE_object.h" #include "BKE_anim.h" /* for duplis */ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_tracking.h" @@ -321,8 +323,9 @@ void applyProject(TransInfo *t) mul_m4_v3(ob->obmat, iloc); } else if (t->flag & T_OBJECT) { + /* TODO(sergey): Ideally force update is not needed here. */ td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(t->scene, td->ob); + BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -393,7 +396,7 @@ void applyGridAbsolute(TransInfo *t) } else if (t->flag & T_OBJECT) { td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(t->scene, td->ob); + BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -1872,7 +1875,7 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(scene, ob, FALSE); + ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { retval |= snapObject(scene, snap_mode, ar, dupli_ob->ob, dupli_ob->mat, false, @@ -2124,7 +2127,7 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(scene, ob, FALSE); + ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { Object *dob = dupli_ob->ob; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index a3813ef4584..24c3291e283 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -851,7 +851,7 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) if (ob->transflag & OB_DUPLI) { DupliObject *dob; - ListBase *lb = object_duplilist(shi->gpumat->scene, ob, FALSE); + ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob); for (dob=lb->first; dob; dob=dob->next) { Object *ob_iter = dob->ob; diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 5053c8082e9..d74cf20c582 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -106,6 +106,7 @@ if env['BF_UNIT_TEST']: if env['WITH_BF_PYTHON']: defs.append('WITH_PYTHON') + incs += ' ../python' if env['WITH_BF_COLLADA']: defs.append('WITH_COLLADA') diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index a4deee5a2c3..26904cac17f 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -158,6 +158,9 @@ endif() if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) + list(APPEND INC + ../../python + ) endif() if(WITH_GAMEENGINE) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 861eca9bd9b..65453556523 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -358,7 +358,13 @@ Mesh *rna_Main_meshes_new_from_object( if (render) { ListBase disp = {NULL, NULL}; - BKE_displist_make_mball_forRender(sce, ob, &disp); + /* TODO(sergey): This is gonna to work for until EvaluationContext + * only contains for_render flag. As soon as CoW is + * implemented, this is to be rethinked. + */ + EvaluationContext eval_ctx = {0}; + eval_ctx.for_render = render; + BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index f29eb7800b5..85e0d91fc71 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -168,6 +168,8 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings) { int for_render = settings == eModifierMode_Render; + EvaluationContext eval_ctx = {0}; + eval_ctx.for_render = for_render; if (!(ob->transflag & OB_DUPLI)) { BKE_report(reports, RPT_ERROR, "Object does not have duplis"); @@ -181,10 +183,10 @@ static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene * free_object_duplilist(ob->duplilist); ob->duplilist = NULL; } - if (G.is_rendering) + if (for_render) dupli_render_particle_set(sce, ob, 0, 1); - ob->duplilist = object_duplilist(sce, ob, for_render); - if (G.is_rendering) + ob->duplilist = object_duplilist(&eval_ctx, sce, ob); + if (for_render) dupli_render_particle_set(sce, ob, 0, 0); /* ob->duplilist should now be freed with Object.free_duplilist */ } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index adc0f7ad892..82447c2e5b4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4514,7 +4514,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_items(prop, display_mode_items); RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - + prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "pic"); RNA_def_property_ui_text(prop, "Output Path", diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index ae6c5e71e6e..a0a0ec96711 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -54,6 +54,10 @@ #include "ED_transform.h" +#ifdef WITH_PYTHON +# include "BPY_extern.h" +#endif + static void rna_Scene_frame_set(Scene *scene, int frame, float subframe) { double cfra = (double)frame + (double)subframe; @@ -61,7 +65,16 @@ static void rna_Scene_frame_set(Scene *scene, int frame, float subframe) CLAMP(cfra, MINAFRAME, MAXFRAME); BKE_scene_frame_set(scene, cfra); - BKE_scene_update_for_newframe(G.main, scene, (1 << 20) - 1); +#ifdef WITH_PYTHON + BPy_BEGIN_ALLOW_THREADS; +#endif + + BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, (1 << 20) - 1); + +#ifdef WITH_PYTHON + BPy_END_ALLOW_THREADS; +#endif + BKE_scene_camera_switch_update(scene); /* don't do notifier when we're rendering, avoid some viewport crashes @@ -78,7 +91,15 @@ static void rna_Scene_frame_set(Scene *scene, int frame, float subframe) static void rna_Scene_update_tagged(Scene *scene) { - BKE_scene_update_tagged(G.main, scene); +#ifdef WITH_PYTHON + BPy_BEGIN_ALLOW_THREADS; +#endif + + BKE_scene_update_tagged(G.main->eval_ctx, G.main, scene); + +#ifdef WITH_PYTHON + BPy_END_ALLOW_THREADS; +#endif } static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name) diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 971b3f0cd14..80caa384086 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -55,6 +55,8 @@ #include "BKE_modifier.h" #include "BKE_object.h" +#include "MOD_util.h" + #include "bmesh.h" #include "depsgraph_private.h" @@ -320,7 +322,7 @@ static void merge_first_last(BMesh *bm, static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, - int UNUSED(initFlags)) + ModifierApplyFlag flag) { DerivedMesh *result; BMesh *bm = DM_to_bmesh(dm, false); @@ -340,9 +342,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, /* need to avoid infinite recursion here */ if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) - start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH); + start_cap = get_dm_for_modifier(amd->start_cap, flag); if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) - end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH); + end_cap = get_dm_for_modifier(amd->end_cap, flag); unit_m4(offset); @@ -571,12 +573,12 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { DerivedMesh *result; ArrayModifierData *amd = (ArrayModifierData *) md; - result = arrayModifier_doArray(amd, md->scene, ob, dm, 0); + result = arrayModifier_doArray(amd, md->scene, ob, dm, flag); return result; } diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index bee7a32f6aa..71a8074c698 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -1,3 +1,4 @@ + /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -119,7 +120,7 @@ static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { BooleanModifierData *bmd = (BooleanModifierData *) md; DerivedMesh *dm; @@ -127,25 +128,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (!bmd->object) return derivedData; - - /* 2.63 used this... */ - /* dm = bmd->object->derivedFinal; */ - - /* but we want to make sure we can get the object - * in some cases the depsgraph fails us - especially for objects - * in other scenes when compositing */ - if (bmd->object != ob) { - /* weak! - but we can too easy end up with circular dep crash otherwise */ - if (bmd->object->type == OB_MESH && modifiers_findByType(bmd->object, eModifierType_Boolean) == NULL) { - dm = mesh_get_derived_final(md->scene, bmd->object, CD_MASK_MESH); - } - else { - dm = bmd->object->derivedFinal; - } - } - else { - dm = NULL; - } + dm = get_dm_for_modifier(bmd->object, flag); if (dm) { DerivedMesh *result; diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index 6e96a160cd4..eebb687aa8d 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -108,17 +108,18 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts, - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; CustomDataMask dataMask = requiredDataMask(ob, md); + bool forRender = (flag & MOD_APPLY_RENDER) != 0; /* ensure we get a CDDM with applied vertex coords */ if (dataMask) { dm = get_cddm(ob, NULL, dm, vertexCos, dependsOnNormals(md)); } - shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts); + shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts, forRender); if (dm != derivedData) dm->release(dm); @@ -135,7 +136,7 @@ static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editD dm = get_cddm(ob, editData, dm, vertexCos, dependsOnNormals(md)); } - shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts); + shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts, false); if (dm != derivedData) dm->release(dm); diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index 22a4c8753d8..fcd4cc96410 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -104,11 +104,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, ModifierApplyFlag flag) { SmokeModifierData *smd = (SmokeModifierData *) md; + bool for_render = (flag & MOD_APPLY_RENDER) != 0; if (flag & MOD_APPLY_ORCO) return dm; - return smokeModifier_do(smd, md->scene, ob, dm); + return smokeModifier_do(smd, md->scene, ob, dm, for_render); } static bool dependsOnTime(ModifierData *UNUSED(md)) diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 62a02928920..bde30fb23ae 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -207,6 +207,20 @@ DerivedMesh *get_dm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, return dm; } +/* Get derived mesh for other object, which is used as an operand for the modifier, + * i.e. second operand for boolean modifier. + */ +DerivedMesh *get_dm_for_modifier(Object *ob, ModifierApplyFlag flag) +{ + if (flag & MOD_APPLY_RENDER) { + /* TODO(sergey): Use proper derived render in the future. */ + return ob->derivedFinal; + } + else { + return ob->derivedFinal; + } +} + void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformVert **dvert, int *defgrp_index) { *defgrp_index = defgroup_name_index(ob, name); diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index b4dcdc1721a..72077b5c000 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -48,6 +48,7 @@ struct DerivedMesh *get_cddm(struct Object *ob, struct BMEditMesh *em, struct De float (*vertexCos)[3], bool use_normals); struct DerivedMesh *get_dm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], bool use_normals, bool use_orco); +struct DerivedMesh *get_dm_for_modifier(struct Object *ob, ModifierApplyFlag flag); void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index); diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 2a43cab7bce..02a9f1eb347 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -52,6 +52,7 @@ #include "BLI_sys_types.h" // for intptr_t support +struct EvaluationContext; struct Object; struct MemArena; struct VertTableNode; @@ -270,6 +271,7 @@ struct Render struct ReportList *reports; struct ImagePool *pool; + struct EvaluationContext *eval_ctx; }; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 1f3e961c151..e3a8c57de66 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -39,8 +39,8 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "BLI_memarena.h" -#include "BLI_ghash.h" #include "BLI_linklist.h" #ifdef WITH_FREESTYLE # include "BLI_edgehash.h" @@ -79,6 +79,7 @@ #include "BKE_constraint.h" #include "BKE_displist.h" #include "BKE_deform.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_effect.h" #include "BKE_global.h" @@ -2221,7 +2222,7 @@ static void init_render_mball(Render *re, ObjectRen *obr) need_orco= 1; } - BKE_displist_make_mball_forRender(re->scene, ob, &dispbase); + BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase); dl= dispbase.first; if (dl == NULL) return; @@ -4981,7 +4982,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp /* create list of duplis generated by this object, particle * system need to have render settings set for dupli particles */ dupli_render_particle_set(re, ob, timeoffset, 0, 1); - lb= object_duplilist(re->scene, ob, TRUE); + lb= object_duplilist(re->eval_ctx, re->scene, ob); dupli_render_particle_set(re, ob, timeoffset, 0, 0); for (dob= lb->first; dob; dob= dob->next) { @@ -5133,12 +5134,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l /* applies changes fully */ if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) - BKE_scene_update_for_newframe(re->main, re->scene, lay); + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay); /* if no camera, viewmat should have been set! */ if (use_camera_view && camera) { /* called before but need to call again in case of lens animation from the - * above call to BKE_scene_update_for_newframe, fixes bug. [#22702]. + * above call to BKE_scene_update_for_newframe_render, fixes bug. [#22702]. * following calls don't depend on 'RE_SetCamera' */ RE_SetCamera(re, camera); @@ -5310,7 +5311,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la /* applies changes fully */ scene->r.cfra += timeoffset; - BKE_scene_update_for_newframe(re->main, re->scene, lay); + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay); /* if no camera, viewmat should have been set! */ if (camera) { diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index c3628e99d04..cccfeed6e47 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -459,7 +459,7 @@ int RE_engine_render(Render *re, int do_all) lay &= non_excluded_lay; } - BKE_scene_update_for_newframe(re->main, re->scene, lay); + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay); } /* create render result */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index ba8265a83fe..4ec7ce1c0d2 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -59,9 +59,11 @@ #include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */ #include "BKE_camera.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_pointcache.h" #include "BKE_report.h" @@ -373,6 +375,8 @@ Render *RE_NewRender(const char *name) BLI_addtail(&RenderGlobal.renderlist, re); BLI_strncpy(re->name, name, RE_MAXNAME); BLI_rw_mutex_init(&re->resultmutex); + re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx"); + re->eval_ctx->for_render = true; } RE_InitRenderCB(re); @@ -420,6 +424,7 @@ void RE_FreeRender(Render *re) render_result_free(re->pushedresult); BLI_remlink(&RenderGlobal.renderlist, re); + MEM_freeN(re->eval_ctx); MEM_freeN(re); } @@ -1320,8 +1325,9 @@ static void do_render_blur_3d(Render *re) re->i.curblur = 0; /* stats */ /* make sure motion blur changes get reset to current frame */ - if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) - BKE_scene_update_for_newframe(re->main, re->scene, re->lay); + if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) { + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay); + } /* weak... the display callback wants an active renderlayer pointer... */ re->result->renlay = render_get_active_layer(re, re->result); @@ -1590,21 +1596,117 @@ static bool rlayer_node_uses_alpha(bNodeTree *ntree, bNode *node) return false; } +/* Issue here is that it's possible that object which is used by boolean, + * array or shrinkwrap modifiers weren't displayed in the viewport before + * rendering. This leads to situations when apply() of this modifiers + * could not get ob->derivedFinal and modifiers are not being applied. + * + * This was worked around by direct call of get_derived_final() from those + * modifiers, but such approach leads to write conflicts with threaded + * update. + * + * Here we make sure derivedFinal will be calculated by update_for_newframe + * function later in the pipeline and all the modifiers are applied + * properly without hacks from their side. + * - sergey - + */ +#define DEPSGRAPH_WORKAROUND_HACK + +#ifdef DEPSGRAPH_WORKAROUND_HACK +static bool allow_render_mesh_object(Object *ob) +{ + /* override not showing object when duplis are used with particles */ + if (ob->transflag & OB_DUPLIPARTS) { + /* pass */ /* let particle system(s) handle showing vs. not showing */ + } + else if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) { + return false; + } + return true; +} + +static void tag_dependend_objects_for_render(Scene *scene, int renderlay) +{ + Scene *sce_iter; + Base *base; + for (SETLOOPER(scene, sce_iter, base)) { + Object *object = base->object; + + if ((base->lay & renderlay) == 0) { + continue; + } + + if (object->type == OB_MESH) { + if (allow_render_mesh_object(object)) { + ModifierData *md; + VirtualModifierData virtualModifierData; + + for (md = modifiers_getVirtualModifierList(object, &virtualModifierData); + md; + md = md->next) + { + if (!modifier_isEnabled(scene, md, eModifierMode_Render)) { + continue; + } + + if (md->type == eModifierType_Boolean) { + BooleanModifierData *bmd = (BooleanModifierData *)md; + if (bmd->object && bmd->object->type == OB_MESH) { + DAG_id_tag_update(&bmd->object->id, OB_RECALC_DATA); + } + } + else if (md->type == eModifierType_Array) { + ArrayModifierData *amd = (ArrayModifierData *)md; + if (amd->start_cap && amd->start_cap->type == OB_MESH) { + DAG_id_tag_update(&amd->start_cap->id, OB_RECALC_DATA); + } + if (amd->end_cap && amd->end_cap->type == OB_MESH) { + DAG_id_tag_update(&amd->end_cap->id, OB_RECALC_DATA); + } + } + else if (md->type == eModifierType_Shrinkwrap) { + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + if (smd->target && smd->target->type == OB_MESH) { + DAG_id_tag_update(&smd->target->id, OB_RECALC_DATA); + } + } + } + } + } + } +} +#endif + static void tag_scenes_for_render(Render *re) { bNode *node; Scene *sce; +#ifdef DEPSGRAPH_WORKAROUND_HACK + int renderlay = re->lay; +#endif - for (sce = re->main->scene.first; sce; sce = sce->id.next) + for (sce = re->main->scene.first; sce; sce = sce->id.next) { sce->id.flag &= ~LIB_DOIT; +#ifdef DEPSGRAPH_WORKAROUND_HACK + tag_dependend_objects_for_render(sce, renderlay); +#endif + } #ifdef WITH_FREESTYLE - for (sce = re->freestyle_bmain.scene.first; sce; sce = sce->id.next) + for (sce = re->freestyle_bmain.scene.first; sce; sce = sce->id.next) { sce->id.flag &= ~LIB_DOIT; +#ifdef DEPSGRAPH_WORKAROUND_HACK + tag_dependend_objects_for_render(sce, renderlay); +#endif + } #endif - if (RE_GetCamera(re) && composite_needs_render(re->scene, 1)) + if (RE_GetCamera(re) && composite_needs_render(re->scene, 1)) { re->scene->id.flag |= LIB_DOIT; +#ifdef DEPSGRAPH_WORKAROUND_HACK + tag_dependend_objects_for_render(re->scene, renderlay); +#endif + } if (re->scene->nodetree == NULL) return; @@ -1632,6 +1734,9 @@ static void tag_scenes_for_render(Render *re) if ((node->id->flag & LIB_DOIT) == 0) { node->flag |= NODE_TEST; node->id->flag |= LIB_DOIT; +#ifdef DEPSGRAPH_WORKAROUND_HACK + tag_dependend_objects_for_render((Scene *) node->id, renderlay); +#endif } } } @@ -2020,7 +2125,7 @@ static void do_render_composite_fields_blur_3d(Render *re) R.stats_draw = re->stats_draw; if (update_newframe) - BKE_scene_update_for_newframe(re->main, re->scene, re->lay); + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay); if (re->r.scemode & R_FULL_SAMPLE) do_merge_fullsample(re, ntree); @@ -2095,14 +2200,12 @@ static void do_render_seq(Render *re) if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) { /* if border rendering is used and cropping is disabled, final buffer should * be as large as the whole frame */ - context = BKE_sequencer_new_render_data(re->main, re->scene, - re->winx, re->winy, - 100); + context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, + re->winx, re->winy, 100); } else { - context = BKE_sequencer_new_render_data(re->main, re->scene, - re->result->rectx, re->result->recty, - 100); + context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, + re->result->rectx, re->result->recty, 100); } out = BKE_sequencer_give_ibuf(context, cfra, 0); @@ -2704,7 +2807,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri else updatelay = re->lay; - BKE_scene_update_for_newframe(bmain, scene, updatelay); + BKE_scene_update_for_newframe(re->eval_ctx, bmain, scene, updatelay); continue; } else diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 8ac8da93584..ee8ad08ad80 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -370,7 +370,7 @@ void wm_event_do_notifiers(bContext *C) /* XXX, hack so operators can enforce datamasks [#26482], gl render */ win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; - BKE_scene_update_tagged(bmain, win->screen->scene); + BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 120f7562f0f..c8c45b3f88a 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -4141,7 +4141,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) if (a & 1) scene->r.cfra--; else scene->r.cfra++; - BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); } else if (type == 5) { @@ -4156,7 +4156,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) if (scene->r.cfra > scene->r.efra) scene->r.cfra = scene->r.sfra; - BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); redraw_timer_window_swap(C); } } diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index af73ccc55bb..ab48e72562e 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -60,6 +60,7 @@ #include "IMB_imbuf.h" #include "BKE_blender.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" @@ -1201,6 +1202,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) IMB_exit(); BKE_images_exit(); + DAG_exit(); totblock = MEM_get_memory_blocks_in_use(); if (totblock != 0) { diff --git a/source/creator/creator.c b/source/creator/creator.c index 3d0b558a502..d7cba36202e 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -1258,6 +1258,7 @@ static int load_file(int UNUSED(argc), const char **argv, void *data) * pointcache works */ if (retval != BKE_READ_FILE_FAIL) { wmWindowManager *wm = CTX_wm_manager(C); + Main *bmain = CTX_data_main(C); /* special case, 2.4x files */ if (wm == NULL && CTX_data_main(C)->wm.first == NULL) { @@ -1273,8 +1274,8 @@ static int load_file(int UNUSED(argc), const char **argv, void *data) G.relbase_valid = 1; if (CTX_wm_manager(C) == NULL) CTX_wm_manager_set(C, wm); /* reset wm */ - DAG_on_visible_update(CTX_data_main(C), TRUE); - BKE_scene_update_tagged(CTX_data_main(C), CTX_data_scene(C)); + DAG_on_visible_update(bmain, TRUE); + BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); } else { /* failed to load file, stop processing arguments */ @@ -1582,6 +1583,7 @@ int main(int argc, const char **argv) IMB_init(); BKE_images_init(); BKE_modifier_init(); + DAG_init(); BKE_brush_system_init(); diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index b04dbc75fe4..57aafede143 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -443,6 +443,7 @@ int main(int argc, char** argv) IMB_init(); BKE_images_init(); BKE_modifier_init(); + DAG_init(); #ifdef WITH_FFMPEG IMB_ffmpeg_init(); @@ -1066,6 +1067,7 @@ int main(int argc, char** argv) IMB_exit(); BKE_images_exit(); + DAG_exit(); SYS_DeleteSystem(syshandle);