Merging r57934 through r57953 from trunk into soc-2013-depsgraph_mt
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 3 Jul 2013 08:31:46 +0000 (08:31 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 3 Jul 2013 08:31:46 +0000 (08:31 +0000)
45 files changed:
release/datafiles/startup.blend
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_depsgraph.h
source/blender/blenkernel/BKE_mball.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/depsgraph_private.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/mball.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/object_deform.c
source/blender/blenkernel/intern/scene.c
source/blender/blenlib/BLI_task.h [new file with mode: 0644]
source/blender/blenlib/BLI_threads.h
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/intern/task.c [new file with mode: 0644]
source/blender/blenlib/intern/threads.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/render/render_internal.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/util/crazyspace.c
source/blender/makesdna/DNA_curve_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_scene.c
source/blender/modifiers/intern/MOD_array.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/creator/creator.c
source/gameengine/GamePlayer/ghost/GPG_ghost.cpp

index c604d16829ce6a5106e895002102e33bd2a83707..8b58493fe3a4a1b8e404ee214d1610104aabbab8 100644 (file)
Binary files a/release/datafiles/startup.blend and b/release/datafiles/startup.blend differ
index 799c109ae0cd0606ce2260c4dc6b786277538132..bf4975f2e43ab4f3b2f54e6cc41cc3a507a76e21 100644 (file)
@@ -70,6 +70,7 @@ class RENDER_PT_render(RenderButtonsPanel, Panel):
         row.operator("render.play_rendered_anim", text="Play", icon='PLAY')
 
         layout.prop(rd, "display_mode", text="Display")
+        layout.prop(rd, "use_lock_interface")
 
 
 class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
index 3be77086336b44c34a97a315229763076f4e3373..6c5bbbd487ea67557d412b68cb73962059e10ab2 100644 (file)
@@ -86,7 +86,7 @@ struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
 float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts);
 float *BKE_curve_surf_make_orco(struct Object *ob);
 
-void BKE_curve_bevelList_make(struct Object *ob);
+void BKE_curve_bevelList_make(struct Object *ob, bool for_render);
 void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob,  struct ListBase *disp, int forRender, int renderResolution);
 
 void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
index 6baf20aeb2c89e4423cbbe35cbd57c9d8c23cef4..f58790c4a1f826a7fa45912891393838ceab842a 100644 (file)
@@ -48,6 +48,7 @@ struct ID;
 struct Main;
 struct Object;
 struct Scene;
+struct ListBase;
 
 /* Build and Update
  *
@@ -115,6 +116,24 @@ 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);
+
+/* Run a callback for every node which is ready for update. */
+void DAG_threaded_update_foreach_ready_node(struct Scene *scene,
+                                            void (*func)(void *node, void *user_data),
+                                            void *user_data);
+
+struct Object *DAG_threaded_update_get_node_object(void *node_v);
+
+const char *DAG_threaded_update_get_node_name(void *node_v);
+
+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);
index 44459300c5640b8d7f6574e373b3b0e4ed97636e..7665e1b54dc6df497daf6cb9ff84889f9f329a38 100644 (file)
@@ -47,7 +47,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);
+void BKE_mball_polygonize(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, bool for_render);
 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);
index 0727e11f3978a6f81812aa76e3c316cc3e40e0b5..8f0d612d473f48effe1113cbec5f1c63bcd8eec4 100644 (file)
@@ -304,6 +304,9 @@ typedef struct ModifierTypeInfo {
                               TexWalkFunc walk, void *userData);
 } ModifierTypeInfo;
 
+/* Initialize modifier's global data (type info and some common global storages). */
+void BKE_modifier_init(void);
+
 ModifierTypeInfo *modifierType_getInfo(ModifierType type);
 
 /* Modifier utility calls, do call through type pointer and return
@@ -377,7 +380,15 @@ struct CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
 struct ModifierData *modifiers_getLastPreview(struct Scene *scene,
                                               struct ModifierData *md,
                                               int required_mode);
-struct ModifierData  *modifiers_getVirtualModifierList(struct Object *ob);
+
+typedef struct VirtualModifierData {
+       ArmatureModifierData amd;
+       CurveModifierData cmd;
+       LatticeModifierData lmd;
+       ShapeKeyModifierData smd;
+} VirtualModifierData;
+
+struct ModifierData  *modifiers_getVirtualModifierList(struct Object *ob, struct VirtualModifierData *data);
 
 /* ensure modifier correctness when changing ob->data */
 void test_object_modifiers(struct Object *ob);
index c8ce2bb2a773376e2bfc10280bf235db020c0178..a47d94f1e7275e513e094bda04470e6ae6ed75c7 100644 (file)
@@ -92,6 +92,13 @@ typedef struct DagNode {
        struct DagAdjList *child;
        struct DagAdjList *parent;
        struct DagNode *next;
+
+       /* Threaded evaluation routines */
+       int valency;        /* valency of the node is a 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.
+                            */
 } DagNode;
 
 typedef struct DagNodeQueueElem {
index 6f86b0c3f887c66e11fc5c599a329d7b4be701bd..a6e28b3df02e5ae2bc5ba00fe6c057013ca9924d 100644 (file)
@@ -49,6 +49,7 @@
 #include "BLI_array.h"
 #include "BLI_utildefines.h"
 #include "BLI_linklist.h"
+#include "BLI_threads.h"
 
 #include "BKE_pbvh.h"
 #include "BKE_cdderivedmesh.h"
@@ -1442,6 +1443,8 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        /* XXX Same as above... For now, only weights preview in WPaint mode. */
        const int do_mod_wmcol = do_init_wmcol;
 
+       VirtualModifierData virtualModifierData;
+
        ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0;
        ModifierApplyFlag deform_app_flags = app_flags;
        if (useCache)
@@ -1453,7 +1456,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                has_multires = 0;
 
        if (!skipVirtualArmature) {
-               firstmd = modifiers_getVirtualModifierList(ob);
+               firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        }
        else {
                /* game engine exception */
@@ -1963,6 +1966,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
        int do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol);
        int do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol);
        const int do_mod_wmcol = do_init_wmcol;
+       VirtualModifierData virtualModifierData;
 
        modifiers_clearErrors(ob);
 
@@ -1971,7 +1975,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
        }
 
        dm = NULL;
-       md = modifiers_getVirtualModifierList(ob);
+       md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        /* copied from mesh_calc_modifiers */
        if (do_mod_wmcol) {
index 9fea3d2e13f507d7dbfa8053844c80b3a4c05db8..8a1eaa66664cd153695e20f697f4e09b65abceb9 100644 (file)
@@ -509,11 +509,11 @@ void calc_curvepath(Object *ob)
        }
        cu = ob->data;
 
-       if (cu->path) free_path(cu->path);
-       cu->path = NULL;
+       if (ob->path) free_path(ob->path);
+       ob->path = NULL;
        
        /* weak! can only use first curve */
-       bl = cu->bev.first;
+       bl = ob->bev.first;
        if (bl == NULL || !bl->nr) {
                return;
        }
@@ -521,7 +521,7 @@ void calc_curvepath(Object *ob)
        nurbs = BKE_curve_nurbs_get(cu);
        nu = nurbs->first;
 
-       cu->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
+       ob->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
        
        /* if POLY: last vertice != first vertice */
        cycl = (bl->poly != -1);
@@ -630,15 +630,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua
 
        if (ob == NULL || ob->type != OB_CURVE) return 0;
        cu = ob->data;
-       if (cu->path == NULL || cu->path->data == NULL) {
+       if (ob->path == NULL || ob->path->data == NULL) {
                printf("no path!\n");
                return 0;
        }
-       path = cu->path;
+       path = ob->path;
        pp = path->data;
        
        /* test for cyclic */
-       bl = cu->bev.first;
+       bl = ob->bev.first;
        if (!bl) return 0;
        if (!bl->nr) return 0;
        if (bl->poly > -1) cycl = 1;
index 8fae35864390a21d3324c789f3a5d6c4f17535e9..fe62127dff50ab5116eb13f09905e237459b57bc 100644 (file)
@@ -1816,18 +1816,16 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
         *     - this is a workaround for a depsgraph bug...
         */
        if (ikData->tar) {
-               Curve *cu = ikData->tar->data;
-
                /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
                 *       currently for paths to work it needs to go through the bevlist/displist system (ton)
                 */
 
                /* only happens on reload file, but violates depsgraph still... fix! */
-               if (ELEM(NULL, cu->path, cu->path->data)) {
+               if (ELEM(NULL, ikData->tar->path, ikData->tar->path->data)) {
                        BKE_displist_make_curveTypes(scene, ikData->tar, 0);
                        
                        /* path building may fail in EditMode after removing verts [#33268]*/
-                       if (ELEM(NULL, cu->path, cu->path->data)) {
+                       if (ELEM(NULL, ikData->tar->path, ikData->tar->path->data)) {
                                /* BLI_assert(cu->path != NULL); */
                                return;
                        }
@@ -1891,7 +1889,6 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
         * since it's easier to determine the positions of all the joints beforehand this way
         */
        if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
-               Curve *cu = (Curve *)ikData->tar->data;
                float splineLen, maxScale;
                int i;
 
@@ -1904,7 +1901,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
 
                /* get the current length of the curve */
                /* NOTE: this is assumed to be correct even after the curve was resized */
-               splineLen = cu->path->totdist;
+               splineLen = ikData->tar->path->totdist;
 
                /* calculate the scale factor to multiply all the path values by so that the
                 * bone chain retains its current length, such that
index 0cd13d528d559fba45a2364f33da23aadd1ede93..6b8cd19639ec8ba32a4604c8fbfb1359f2521b2c 100644 (file)
@@ -1164,10 +1164,10 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
                 */
                
                /* only happens on reload file, but violates depsgraph still... fix! */
-               if (cu->path == NULL || cu->path->data == NULL)
+               if (ct->tar->path == NULL || ct->tar->path->data == NULL)
                        BKE_displist_make_curveTypes(cob->scene, ct->tar, 0);
                
-               if (cu->path && cu->path->data) {
+               if (ct->tar->path && ct->tar->path->data) {
                        float quat[4];
                        if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
                                /* animated position along curve depending on time */
@@ -1934,10 +1934,8 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
        if (VALID_CONS_TARGET(ct)) {
                /* special exception for curves - depsgraph issues */
                if (ct->tar->type == OB_CURVE) {
-                       Curve *cu = ct->tar->data;
-                       
                        /* this check is to make sure curve objects get updated on file load correctly.*/
-                       if (cu->path == NULL || cu->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
+                       if (ct->tar->path == NULL || ct->tar->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
                                BKE_displist_make_curveTypes(cob->scene, ct->tar, 0);
                }
                
@@ -3008,14 +3006,12 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, short nocopy)
 static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 {
        if (VALID_CONS_TARGET(ct)) {
-               Curve *cu = ct->tar->data;
-               
                /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
                 *              currently for paths to work it needs to go through the bevlist/displist system (ton) 
                 */
                
                /* only happens on reload file, but violates depsgraph still... fix! */
-               if (cu->path == NULL || cu->path->data == NULL)
+               if (ct->tar->path == NULL || ct->tar->path->data == NULL)
                        BKE_displist_make_curveTypes(cob->scene, ct->tar, 0);
        }
        
@@ -3033,7 +3029,6 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
        
        /* only evaluate if there is a target and it is a curve */
        if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
-               Curve *cu = data->tar->data;
                float obmat[4][4], ownLoc[3];
                float curveMin[3], curveMax[3];
                float targetMatrix[4][4] = MAT4_UNITY;
@@ -3046,7 +3041,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
                BKE_object_minmax(ct->tar, curveMin, curveMax, TRUE);
                
                /* get targetmatrix */
-               if (cu->path && cu->path->data) {
+               if (data->tar->path && data->tar->path->data) {
                        float vec[4], dir[3], totmat[4][4];
                        float curvetime;
                        short clamp_axis;
@@ -3649,14 +3644,12 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, short nocopy)
 static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 {
        if (VALID_CONS_TARGET(ct)) {
-               Curve *cu = ct->tar->data;
-               
                /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
                 *              currently for paths to work it needs to go through the bevlist/displist system (ton) 
                 */
                
                /* only happens on reload file, but violates depsgraph still... fix! */
-               if (cu->path == NULL || cu->path->data == NULL)
+               if (ct->tar->path == NULL || ct->tar->path->data == NULL)
                        BKE_displist_make_curveTypes(cob->scene, ct->tar, 0);
        }
        
index 3b9fbbb1c4d98948dfbb57ee9ff707250fbc7089..ea8f49a319963ba0789639a3dd8fed20e63d615a 100644 (file)
@@ -145,8 +145,6 @@ void BKE_curve_editNurb_free(Curve *cu)
 void BKE_curve_free(Curve *cu)
 {
        BKE_nurbList_free(&cu->nurb);
-       BLI_freelistN(&cu->bev);
-       BKE_displist_free(&cu->disp);
        BKE_curve_editfont_free(cu);
 
        BKE_curve_editNurb_free(cu);
@@ -161,8 +159,6 @@ void BKE_curve_free(Curve *cu)
                MEM_freeN(cu->strinfo);
        if (cu->bb)
                MEM_freeN(cu->bb);
-       if (cu->path)
-               free_path(cu->path);
        if (cu->tb)
                MEM_freeN(cu->tb);
 }
@@ -228,10 +224,6 @@ Curve *BKE_curve_copy(Curve *cu)
        cun->key = BKE_key_copy(cu->key);
        if (cun->key) cun->key->from = (ID *)cun;
 
-       cun->disp.first = cun->disp.last = NULL;
-       cun->bev.first = cun->bev.last = NULL;
-       cun->path = NULL;
-
        cun->editnurb = NULL;
        cun->editfont = NULL;
        cun->selboxes = NULL;
@@ -374,36 +366,14 @@ void BKE_curve_type_test(Object *ob)
 
 void BKE_curve_texspace_calc(Curve *cu)
 {
-       DispList *dl;
-       BoundBox *bb;
-       float *fp, min[3], max[3];
-       int tot, do_it = FALSE;
-
-       if (cu->bb == NULL)
-               cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
-       bb = cu->bb;
-
-       INIT_MINMAX(min, max);
-
-       dl = cu->disp.first;
-       while (dl) {
-               tot = ELEM(dl->type, DL_INDEX3, DL_INDEX4) ? dl->nr : dl->nr * dl->parts;
-
-               if (tot) do_it = TRUE;
-               fp = dl->verts;
-               while (tot--) {
-                       minmax_v3v3_v3(min, max, fp);
-                       fp += 3;
-               }
-               dl = dl->next;
-       }
-
-       if (do_it == FALSE) {
-               min[0] = min[1] = min[2] = -1.0f;
-               max[0] = max[1] = max[2] = 1.0f;
-       }
+       BoundBox *bb = cu->bb;
+       float min[3], max[3];
 
-       BKE_boundbox_init_from_minmax(bb, min, max);
+       /* Curve's undeformed bounding box is calculated in displist.c,
+        * as a part of display list calculation.
+        */
+       copy_v3_v3(min, bb->vec[0]);
+       copy_v3_v3(max, bb->vec[6]);
 
        if (cu->texflag & CU_AUTOSPACE) {
                mid_v3_v3v3(cu->loc, min, max);
@@ -2269,7 +2239,7 @@ static void make_bevel_list_2D(BevList *bl)
        }
 }
 
-void BKE_curve_bevelList_make(Object *ob)
+void BKE_curve_bevelList_make(Object *ob, bool for_render)
 {
        /*
         * - convert all curves to polys, with indication of resol and flags for double-vertices
@@ -2288,16 +2258,19 @@ void BKE_curve_bevelList_make(Object *ob)
        int a, b, nr, poly, resolu = 0, len = 0;
        int do_tilt, do_radius, do_weight;
        int is_editmode = 0;
+       ListBase *bev;
 
        /* this function needs an object, because of tflag and upflag */
        cu = ob->data;
 
+       bev = &ob->bev;
+
        /* do we need to calculate the radius for each point? */
        /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
 
        /* STEP 1: MAKE POLYS  */
 
-       BLI_freelistN(&(cu->bev));
+       BLI_freelistN(&(ob->bev));
        if (cu->editnurb && ob->type != OB_FONT) {
                ListBase *nurbs = BKE_curve_editNurbs_get(cu);
                nu = nurbs->first;
@@ -2321,11 +2294,11 @@ void BKE_curve_bevelList_make(Object *ob)
                 * enforced in the UI but can go wrong possibly */
                if (!BKE_nurb_check_valid_u(nu)) {
                        bl = MEM_callocN(sizeof(BevList) + 1 * sizeof(BevPoint), "makeBevelList1");
-                       BLI_addtail(&(cu->bev), bl);
+                       BLI_addtail(bev, bl);
                        bl->nr = 0;
                }
                else {
-                       if (G.is_rendering && cu->resolu_ren != 0)
+                       if (for_render && cu->resolu_ren != 0)
                                resolu = cu->resolu_ren;
                        else
                                resolu = nu->resolu;
@@ -2333,7 +2306,7 @@ void BKE_curve_bevelList_make(Object *ob)
                        if (nu->type == CU_POLY) {
                                len = nu->pntsu;
                                bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2");
-                               BLI_addtail(&(cu->bev), bl);
+                               BLI_addtail(bev, bl);
 
                                if (nu->flagu & CU_NURB_CYCLIC) bl->poly = 0;
                                else bl->poly = -1;
@@ -2356,7 +2329,7 @@ void BKE_curve_bevelList_make(Object *ob)
                                /* in case last point is not cyclic */
                                len = resolu * (nu->pntsu + (nu->flagu & CU_NURB_CYCLIC) - 1) + 1;
                                bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints");
-                               BLI_addtail(&(cu->bev), bl);
+                               BLI_addtail(bev, bl);
 
                                if (nu->flagu & CU_NURB_CYCLIC) bl->poly = 0;
                                else bl->poly = -1;
@@ -2442,7 +2415,7 @@ void BKE_curve_bevelList_make(Object *ob)
                                        len = (resolu * SEGMENTSU(nu));
 
                                        bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3");
-                                       BLI_addtail(&(cu->bev), bl);
+                                       BLI_addtail(bev, bl);
                                        bl->nr = len;
                                        bl->dupe_nr = 0;
                                        if (nu->flagu & CU_NURB_CYCLIC) bl->poly = 0;
@@ -2460,7 +2433,7 @@ void BKE_curve_bevelList_make(Object *ob)
        }
 
        /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
-       bl = cu->bev.first;
+       bl = bev->first;
        while (bl) {
                if (bl->nr) { /* null bevel items come from single points */
                        nr = bl->nr;
@@ -2482,7 +2455,7 @@ void BKE_curve_bevelList_make(Object *ob)
                }
                bl = bl->next;
        }
-       bl = cu->bev.first;
+       bl = bev->first;
        while (bl) {
                blnext = bl->next;
                if (bl->nr && bl->dupe_nr) {
@@ -2490,8 +2463,8 @@ void BKE_curve_bevelList_make(Object *ob)
                        blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4");
                        memcpy(blnew, bl, sizeof(BevList));
                        blnew->nr = 0;
-                       BLI_remlink(&(cu->bev), bl);
-                       BLI_insertlinkbefore(&(cu->bev), blnext, blnew);    /* to make sure bevlijst is tuned with nurblist */
+                       BLI_remlink(bev, bl);
+                       BLI_insertlinkbefore(bev, blnext, blnew);    /* to make sure bevlijst is tuned with nurblist */
                        bevp0 = (BevPoint *)(bl + 1);
                        bevp1 = (BevPoint *)(blnew + 1);
                        nr = bl->nr;
@@ -2510,7 +2483,7 @@ void BKE_curve_bevelList_make(Object *ob)
        }
 
        /* STEP 3: POLYS COUNT AND AUTOHOLE */
-       bl = cu->bev.first;
+       bl = bev->first;
        poly = 0;
        while (bl) {
                if (bl->nr && bl->poly >= 0) {
@@ -2524,7 +2497,7 @@ void BKE_curve_bevelList_make(Object *ob)
        /* find extreme left points, also test (turning) direction */
        if (poly > 0) {
                sd = sortdata = MEM_mallocN(sizeof(struct bevelsort) * poly, "makeBevelList5");
-               bl = cu->bev.first;
+               bl = bev->first;
                while (bl) {
                        if (bl->poly > 0) {
 
@@ -2602,7 +2575,7 @@ void BKE_curve_bevelList_make(Object *ob)
        /* STEP 4: 2D-COSINES or 3D ORIENTATION */
        if ((cu->flag & CU_3D) == 0) {
                /* 2D Curves */
-               for (bl = cu->bev.first; bl; bl = bl->next) {
+               for (bl = bev->first; bl; bl = bl->next) {
                        if (bl->nr < 2) {
                                /* do nothing */
                        }
@@ -2616,7 +2589,7 @@ void BKE_curve_bevelList_make(Object *ob)
        }
        else {
                /* 3D Curves */
-               for (bl = cu->bev.first; bl; bl = bl->next) {
+               for (bl = bev->first; bl; bl = bl->next) {
                        if (bl->nr < 2) {
                                /* do nothing */
                        }
index 2206770dfbd7b064bf54aac0d46f211c9f62e398..ce2047cb7af7aedb9bf342018a17338ffa3b51da 100644 (file)
@@ -29,6 +29,7 @@
 
  
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <math.h>
 
@@ -2652,6 +2653,123 @@ void DAG_pose_sort(Object *ob)
        ugly_hack_sorry = 1;
 }
 
+/* ************************  DAG FOR THREADED UPDATE  ********************* */
+
+/* Initialize the DAG for threaded update.
+ *
+ * Sets up all the data needed for faster check whether DAG node is
+ * updatable already (whether all the dependencies are met).
+ */
+void DAG_threaded_update_begin(Scene *scene)
+{
+       DagNode *node;
+
+       /* We reset valency to zero first... */
+       for (node = scene->theDag->DagNode.first; node; node = node->next) {
+               node->valency = 0;
+       }
+
+       /* ... and then iterate over all the nodes and
+        * increase valency 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->valency++;
+                       }
+               }
+       }
+
+       /* A bit tricky, tasks are operating with nodes, which is much
+        * easier from tracking dependnecies point of view, and also
+        * makes it possible to do partial object objects.
+        *
+        * However, currently the only way we're performing update is
+        * calling object_handle_update for objects which are ready,
+        * which also updates object data.
+        *
+        * And for this we need to know whether node represents object
+        * or not.
+        *
+        * And we mark all the nodes which represents objects as
+        * white color, All other nodes are staying gray.
+        */
+       for (node = scene->theDag->DagNode.first; node; node = node->next) {
+               Base *base = scene->base.first;
+               node->color = DAG_GRAY;
+               while (base && base->object != node->ob) {
+                       base = base->next;
+               }
+               if (base) {
+                       node->color = DAG_WHITE;
+               }
+       }
+}
+
+/* Call functor for every node in the graph which is ready for
+ * update (all it's dependencies are met). Quick check for this
+ * is valency == 0.
+ */
+void DAG_threaded_update_foreach_ready_node(Scene *scene,
+                                            void (*func)(void *node, void *user_data),
+                                            void *user_data)
+{
+       DagNode *node;
+
+       for (node = scene->theDag->DagNode.first; node; node = node->next) {
+               if (node->valency == 0) {
+                       func(node, user_data);
+               }
+       }
+}
+
+/* Will return Object ID if node represents Object,
+ * and will return NULL otherwise.
+ */
+Object *DAG_threaded_update_get_node_object(void *node_v)
+{
+       DagNode *node = node_v;
+
+       if (node->color == DAG_WHITE) {
+               return node->ob;
+       }
+
+       return NULL;
+}
+
+/* Returns node name, used for debug output only, atm. */
+const char *DAG_threaded_update_get_node_name(void *node_v)
+{
+       DagNode *node = node_v;
+
+       return dag_node_name(node);
+}
+
+/* This function is called when handling node is done.
+ *
+ * This function updates valency 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) {
+               if (itA->node != node) {
+                       itA->node->valency--;
+
+                       if (itA->node->valency == 0) {
+                               func(itA->node, user_data);
+                       }
+               }
+       }
+}
+
 /* ************************ DAG DEBUGGING ********************* */
 
 void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob)
@@ -2670,4 +2788,3 @@ void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob)
        
        dag_print_dependencies = 0;
 }
-
index 38a0b8483397a4e9c588b7e0a60e1f08146a307e..058122c21aa6d8adb53a73527211e4c64e422cab 100644 (file)
@@ -45,6 +45,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
 #include "BLI_scanfill.h"
+#include "BLI_threads.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_global.h"
@@ -62,8 +63,8 @@
 
 #include "BLI_sys_types.h" // for intptr_t support
 
-static void boundbox_displist(Object *ob);
 static void boundbox_dispbase(BoundBox *bb, ListBase *dispbase);
+static void boundbox_displist_object(Object *ob);
 
 void BKE_displist_elem_free(DispList *dl)
 {
@@ -712,29 +713,23 @@ void BKE_displist_make_mball(Scene *scene, Object *ob)
        if (!ob || ob->type != OB_MBALL)
                return;
 
-       /* XXX: mball stuff uses plenty of global variables
-        *      while this is unchanged updating during render is unsafe
-        */
-       if (G.is_rendering)
-               return;
-
        BKE_displist_free(&(ob->disp));
 
        if (ob->type == OB_MBALL) {
                if (ob == BKE_mball_basis_find(scene, ob)) {
-                       BKE_mball_polygonize(scene, ob, &ob->disp);
+                       BKE_mball_polygonize(scene, ob, &ob->disp, false);
                        BKE_mball_texspace_calc(ob);
 
                        object_deform_mball(ob, &ob->disp);
                }
-       }
 
-       boundbox_displist(ob);
+               boundbox_displist_object(ob);
+       }
 }
 
 void BKE_displist_make_mball_forRender(Scene *scene, Object *ob, ListBase *dispbase)
 {
-       BKE_mball_polygonize(scene, ob, dispbase);
+       BKE_mball_polygonize(scene, ob, dispbase, true);
        BKE_mball_texspace_calc(ob);
 
        object_deform_mball(ob, dispbase);
@@ -742,7 +737,8 @@ void BKE_displist_make_mball_forRender(Scene *scene, Object *ob, ListBase *dispb
 
 static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, int renderResolution, int editmode)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        int required_mode;
 
@@ -784,7 +780,8 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in
                                      float (**originalVerts_r)[3],
                                      float (**deformedVerts_r)[3], int *numVerts_r)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        Curve *cu = ob->data;
        ListBase *nurb = BKE_curve_nurbs_get(cu);
@@ -898,7 +895,8 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
                                       int forRender, int renderResolution,
                                       float (*originalVerts)[3], float (*deformedVerts)[3])
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        Curve *cu = ob->data;
        ListBase *nurb = BKE_curve_nurbs_get(cu);
@@ -1142,8 +1140,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *derivedFina
        /* this function represents logic of mesh's orcodm calculation
         * for displist-based objects
         */
-
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        Curve *cu = ob->data;
        int required_mode;
@@ -1282,10 +1280,11 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
                }
        }
 
-       /* make copy of 'undeformed" displist for texture space calculation
-        * actually, it's not totally undeformed -- pre-tessellation modifiers are
-        * already applied, thats how it worked for years, so keep for compatibility (sergey) */
-       BKE_displist_copy(&cu->disp, dispbase);
+       /* Calculate curve's boundig box from non-modified display list. */
+       if (cu->bb == NULL) {
+               cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
+       }
+       boundbox_dispbase(cu->bb, dispbase);
 
        if (!forRender) {
                BKE_curve_texspace_calc(cu);
@@ -1396,10 +1395,13 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
 
                nubase = BKE_curve_nurbs_get(cu);
 
-               BLI_freelistN(&(cu->bev));
+               /* XXX: Temp workaround for depsgraph_mt branch. */
+               BLI_lock_thread(LOCK_CUSTOM1);
 
-               if (cu->path) free_path(cu->path);
-               cu->path = NULL;
+               BLI_freelistN(&(ob->bev));
+
+               if (ob->path) free_path(ob->path);
+               ob->path = NULL;
 
                if (ob->type == OB_FONT)
                        BKE_vfont_to_curve(G.main, scene, ob, 0);
@@ -1407,7 +1409,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                if (!forOrco)
                        curve_calc_modifiers_pre(scene, ob, forRender, renderResolution, &originalVerts, &deformedVerts, &numVerts);
 
-               BKE_curve_bevelList_make(ob);
+               BKE_curve_bevelList_make(ob, forRender != FALSE);
 
                /* If curve has no bevel will return nothing */
                BKE_curve_bevel_make(scene, ob, &dlbev, forRender, renderResolution);
@@ -1418,7 +1420,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                }
                else {
                        float widfac = cu->width - 1.0f;
-                       BevList *bl = cu->bev.first;
+                       BevList *bl = ob->bev.first;
                        Nurb *nu = nubase->first;
 
                        for (; bl && nu; bl = bl->next, nu = nu->next) {
@@ -1592,10 +1594,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                if ((cu->flag & CU_PATH) && !forOrco)
                        calc_curvepath(ob);
 
-               /* make copy of 'undeformed" displist for texture space calculation
-                * actually, it's not totally undeformed -- pre-tessellation modifiers are
-                * already applied, thats how it worked for years, so keep for compatibility (sergey) */
-               BKE_displist_copy(&cu->disp, dispbase);
+               /* Calculate curve's boundig box from non-modified display list. */
+               if (cu->bb == NULL) {
+                       cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
+               }
+
+               boundbox_dispbase(cu->bb, dispbase);
 
                if (!forRender) {
                        BKE_curve_texspace_calc(cu);
@@ -1604,6 +1608,9 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                if (!forOrco)
                        curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal, forRender, renderResolution, originalVerts, deformedVerts);
 
+               /* XXX: Temp workaround for depsgraph_mt branch. */
+               BLI_unlock_thread(LOCK_CUSTOM1);
+
                if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
                        curve_to_filledpoly(cu, nubase, dispbase);
                }
@@ -1612,7 +1619,6 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
 
 void BKE_displist_make_curveTypes(Scene *scene, Object *ob, int forOrco)
 {
-       Curve *cu = ob->data;
        ListBase *dispbase;
 
        /* The same check for duplis as in do_makeDispListCurveTypes.
@@ -1625,23 +1631,9 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, int forOrco)
        dispbase = &(ob->disp);
        BKE_displist_free(dispbase);
 
-       /* free displist used for textspace */
-       BKE_displist_free(&cu->disp);
-
        do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, forOrco, 0);
 
-       if (ob->derivedFinal) {
-               DM_set_object_boundbox(ob, ob->derivedFinal);
-
-               /* always keep curve's  BB in sync with non-deformed displist */
-               if (cu->bb == NULL)
-                       cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
-
-               boundbox_dispbase(cu->bb, &cu->disp);
-       }
-       else {
-               boundbox_displist(ob);
-       }
+       boundbox_displist_object(ob);
 }
 
 void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
@@ -1705,21 +1697,22 @@ static void boundbox_dispbase(BoundBox *bb, ListBase *dispbase)
 }
 
 /* this is confusing, there's also min_max_object, appplying the obmat... */
-static void boundbox_displist(Object *ob)
+static void boundbox_displist_object(Object *ob)
 {
        if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
-               Curve *cu = ob->data;
-
-               /* calculate curve's BB based on non-deformed displist */
-               if (cu->bb == NULL)
-                       cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
-
-               boundbox_dispbase(cu->bb, &cu->disp);
+               /* Curver's BB is already calculated as a part of modifier stack,
+                * here we only calculate object BB based on final display list.
+                */
 
                /* object's BB is calculated from final displist */
                if (ob->bb == NULL)
                        ob->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
 
-               boundbox_dispbase(ob->bb, &ob->disp);
+               if (ob->derivedFinal) {
+                       DM_set_object_boundbox(ob, ob->derivedFinal);
+               }
+               else {
+                       boundbox_dispbase(ob->bb, &ob->disp);
+               }
        }
 }
index 02d1621e408b0fe547fe9de1e6c178e9fee99bb7..1a2c368a7d46f72d20ed0668733d824a66dbce7d 100644 (file)
@@ -176,10 +176,10 @@ static void precalculate_effector(EffectorCache *eff)
        if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
                Curve *cu= eff->ob->data;
                if (cu->flag & CU_PATH) {
-                       if (cu->path==NULL || cu->path->data==NULL)
+                       if (eff->ob->path==NULL || eff->ob->path->data==NULL)
                                BKE_displist_make_curveTypes(eff->scene, eff->ob, 0);
 
-                       if (cu->path && cu->path->data) {
+                       if (eff->ob->path && eff->ob->path->data) {
                                where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
                                mul_m4_v3(eff->ob->obmat, eff->guide_loc);
                                mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
index b3edeb67928355faa610ad118e8bb3c0598243d3..24cbe1e19ab44b0bdac9816df80da119b216e61e 100644 (file)
@@ -819,8 +819,8 @@ makebreak:
                
                cucu->flag |= (CU_PATH + CU_FOLLOW);
                
-               if (cucu->path == NULL) BKE_displist_make_curveTypes(scene, cu->textoncurve, 0);
-               if (cucu->path) {
+               if (cu->textoncurve->path == NULL) BKE_displist_make_curveTypes(scene, cu->textoncurve, 0);
+               if (cu->textoncurve->path) {
                        float distfac, imat[4][4], imat3[3][3], cmat[3][3];
                        float minx, maxx, miny, maxy;
                        float timeofs, sizefac;
@@ -845,7 +845,7 @@ makebreak:
                        /* we put the x-coordinaat exact at the curve, the y is rotated */
                        
                        /* length correction */
-                       distfac = sizefac * cucu->path->totdist / (maxx - minx);
+                       distfac = sizefac * cu->textoncurve->path->totdist / (maxx - minx);
                        timeofs = 0.0f;
                        
                        if (distfac > 1.0f) {
index c9b904e76ac3bb47e7704bc64020e61826d71512..abe5a153b9e9e52137a87c4df2ae395d26846a94 100644 (file)
@@ -506,13 +506,12 @@ static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
  */
 static int where_on_path_deform(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
 {
-       Curve *cu = ob->data;
        BevList *bl;
        float ctime1;
        int cycl = 0;
        
        /* test for cyclic */
-       bl = cu->bev.first;
+       bl = ob->bev.first;
        if (!bl->nr) return 0;
        if (bl->poly > -1) cycl = 1;
 
@@ -527,7 +526,7 @@ static int where_on_path_deform(Object *ob, float ctime, float vec[4], float dir
        if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
                
                if (cycl == 0) {
-                       Path *path = cu->path;
+                       Path *path = ob->path;
                        float dvec[3];
                        
                        if (ctime < 0.0f) {
@@ -565,9 +564,9 @@ static int calc_curve_deform(Scene *scene, Object *par, float co[3],
        const int is_neg_axis = (axis > 2);
 
        /* to be sure, mostly after file load */
-       if (cu->path == NULL) {
+       if (par->path == NULL) {
                BKE_displist_make_curveTypes(scene, par, 0);
-               if (cu->path == NULL) return 0;  // happens on append...
+               if (par->path == NULL) return 0;  // happens on append...
        }
        
        /* options */
@@ -576,14 +575,14 @@ static int calc_curve_deform(Scene *scene, Object *par, float co[3],
                if (cu->flag & CU_STRETCH)
                        fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
                else
-                       fac = -(co[index] - cd->dmax[index]) / (cu->path->totdist);
+                       fac = -(co[index] - cd->dmax[index]) / (par->path->totdist);
        }
        else {
                index = axis;
                if (cu->flag & CU_STRETCH)
                        fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
                else
-                       fac = +(co[index] - cd->dmin[index]) / (cu->path->totdist);
+                       fac = +(co[index] - cd->dmin[index]) / (par->path->totdist);
        }
        
        if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) {  /* returns OK */
@@ -991,7 +990,8 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3])
 void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
 {
        Lattice *lt = ob->data;
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        float (*vertexCos)[3] = NULL;
        int numVerts, editmode = (lt->editlatt != NULL);
 
index 31212c3a6b79b7fb71c0724444fdcd87db918da7..f84a6088ee53e875f8a4568931fbc3547dcdf7b7 100644 (file)
@@ -2269,7 +2269,7 @@ static void mball_count(PROCESS *process, Scene *scene, Object *basis)
        }
 }
 
-void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for_render)
 {
        MetaBall *mb;
        DispList *dl;
@@ -2282,7 +2282,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase)
        mball_count(&process, scene, ob);
 
        if (process.totelem == 0) return;
-       if ((G.is_rendering == FALSE) && (mb->flag == MB_UPDATE_NEVER)) return;
+       if ((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;
@@ -2320,7 +2320,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase)
        }
 
        /* width is size per polygonize cube */
-       if (G.is_rendering) {
+       if (for_render) {
                width = mb->rendersize;
        }
        else {
index a0fa33172971e07e94a4e0ec14a52da926f3da1f..802f467d1687f1eef98ba70305e0b6d29a85e0fb 100644 (file)
 
 #include "MOD_modifiertypes.h"
 
-ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
+static VirtualModifierData virtualModifierCommonData;
+
+void BKE_modifier_init(void)
 {
-       static ModifierTypeInfo *types[NUM_MODIFIER_TYPES] = {NULL};
-       static int types_init = 1;
+       ModifierData *md;
 
-       if (types_init) {
-               modifier_type_init(types); /* MOD_utils.c */
-               types_init = 0;
-       }
+       /* Initialize modifier types */
+       modifier_type_init(modifier_types); /* MOD_utils.c */
+
+       /* Initialize global cmmon storage used for virtual modifier list */
+       md = modifier_new(eModifierType_Armature);
+       virtualModifierCommonData.amd = *((ArmatureModifierData *) md);
+       modifier_free(md);
+
+       md = modifier_new(eModifierType_Curve);
+       virtualModifierCommonData.cmd = *((CurveModifierData *) md);
+       modifier_free(md);
 
+       md = modifier_new(eModifierType_Lattice);
+       virtualModifierCommonData.lmd = *((LatticeModifierData *) md);
+       modifier_free(md);
+
+       md = modifier_new(eModifierType_ShapeKey);
+       virtualModifierCommonData.smd = *((ShapeKeyModifierData *) md);
+       modifier_free(md);
+
+       virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
+       virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
+       virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual;
+       virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
+}
+
+ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+{
        /* type unsigned, no need to check < 0 */
-       if (type < NUM_MODIFIER_TYPES && types[type]->name[0] != '\0') {
-               return types[type];
+       if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
+               return modifier_types[type];
        }
        else {
                return NULL;
@@ -289,7 +314,8 @@ void modifier_setError(ModifierData *md, const char *_format, ...)
  */
 int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *lastPossibleCageIndex_r, int virtual_)
 {
-       ModifierData *md = (virtual_) ? modifiers_getVirtualModifierList(ob) : ob->modifiers.first;
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = (virtual_) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) : ob->modifiers.first;
        int i, cageIndex = -1;
 
        if (lastPossibleCageIndex_r) {
@@ -435,74 +461,43 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
 /* NOTE: This is to support old files from before Blender supported modifiers,
  * in some cases versioning code updates these so for new files this will
  * return an empty list. */
-ModifierData *modifiers_getVirtualModifierList(Object *ob)
+ModifierData *modifiers_getVirtualModifierList(Object *ob, VirtualModifierData *virtualModifierData)
 {
-       /* Kinda hacky, but should be fine since we are never
-        * re-entrant and avoid free hassles.
-        */
-       static ArmatureModifierData amd;
-       static CurveModifierData cmd;
-       static LatticeModifierData lmd;
-       static ShapeKeyModifierData smd;
-       static int init = 1;
        ModifierData *md;
 
-       if (init) {
-               md = modifier_new(eModifierType_Armature);
-               amd = *((ArmatureModifierData *) md);
-               modifier_free(md);
-
-               md = modifier_new(eModifierType_Curve);
-               cmd = *((CurveModifierData *) md);
-               modifier_free(md);
-
-               md = modifier_new(eModifierType_Lattice);
-               lmd = *((LatticeModifierData *) md);
-               modifier_free(md);
-
-               md = modifier_new(eModifierType_ShapeKey);
-               smd = *((ShapeKeyModifierData *) md);
-               modifier_free(md);
-
-               amd.modifier.mode |= eModifierMode_Virtual;
-               cmd.modifier.mode |= eModifierMode_Virtual;
-               lmd.modifier.mode |= eModifierMode_Virtual;
-               smd.modifier.mode |= eModifierMode_Virtual;
-
-               init = 0;
-       }
-
        md = ob->modifiers.first;
 
+       *virtualModifierData = virtualModifierCommonData;
+
        if (ob->parent) {
                if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) {
-                       amd.object = ob->parent;
-                       amd.modifier.next = md;
-                       amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
-                       md = &amd.modifier;
+                       virtualModifierData->amd.object = ob->parent;
+                       virtualModifierData->amd.modifier.next = md;
+                       virtualModifierData->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
+                       md = &virtualModifierData->amd.modifier;
                }
                else if (ob->parent->type == OB_CURVE && ob->partype == PARSKEL) {
-                       cmd.object = ob->parent;
-                       cmd.defaxis = ob->trackflag + 1;
-                       cmd.modifier.next = md;
-                       md = &cmd.modifier;
+                       virtualModifierData->cmd.object = ob->parent;
+                       virtualModifierData->cmd.defaxis = ob->trackflag + 1;
+                       virtualModifierData->cmd.modifier.next = md;
+                       md = &virtualModifierData->cmd.modifier;
                }
                else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
-                       lmd.object = ob->parent;
-                       lmd.modifier.next = md;
-                       md = &lmd.modifier;
+                       virtualModifierData->lmd.object = ob->parent;
+                       virtualModifierData->lmd.modifier.next = md;
+                       md = &virtualModifierData->lmd.modifier;
                }
        }
 
        /* shape key modifier, not yet for curves */
        if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object(ob)) {
                if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE))
-                       smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
+                       virtualModifierData->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
                else
-                       smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
+                       virtualModifierData->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
 
-               smd.modifier.next = md;
-               md = &smd.modifier;
+               virtualModifierData->smd.modifier.next = md;
+               md = &virtualModifierData->smd.modifier;
        }
 
        return md;
@@ -513,7 +508,8 @@ ModifierData *modifiers_getVirtualModifierList(Object *ob)
  */
 Object *modifiers_isDeformedByArmature(Object *ob)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ArmatureModifierData *amd = NULL;
        
        /* return the first selected armature, this lets us use multiple armatures */
@@ -536,7 +532,8 @@ Object *modifiers_isDeformedByArmature(Object *ob)
  */
 Object *modifiers_isDeformedByLattice(Object *ob)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        LatticeModifierData *lmd = NULL;
        
        /* return the first selected lattice, this lets us use multiple lattices */
@@ -559,7 +556,8 @@ Object *modifiers_isDeformedByLattice(Object *ob)
  */
 Object *modifiers_isDeformedByCurve(Object *ob)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        CurveModifierData *cmd = NULL;
        
        /* return the first selected curve, this lets us use multiple curves */
@@ -579,7 +577,8 @@ Object *modifiers_isDeformedByCurve(Object *ob)
 
 bool modifiers_usesArmature(Object *ob, bArmature *arm)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        for (; md; md = md->next) {
                if (md->type == eModifierType_Armature) {
@@ -604,7 +603,8 @@ bool modifier_isCorrectableDeformed(ModifierData *md)
 
 bool modifiers_isCorrectableDeformed(Object *ob)
 {
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
+       VirtualModifierData virtualModifierData;
+       ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        
        for (; md; md = md->next) {
                if (ob->mode == OB_MODE_EDIT && (md->mode & eModifierMode_Editmode) == 0) {
index f1183868e8b3b28e06594fda4dff0c6594d76e8d..875217e94dd3a655be4013a9e216450d388dc15f 100644 (file)
@@ -340,6 +340,11 @@ void BKE_object_free(Object *ob)
        free_sculptsession(ob);
 
        if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
+
+       /* Free runtime curves data. */
+       BLI_freelistN(&ob->bev);
+       if (ob->path)
+               free_path(ob->path);
 }
 
 static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin)
@@ -1273,7 +1278,11 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, int copy_caches)
        obn->pc_ids.first = obn->pc_ids.last = NULL;
 
        obn->mpath = NULL;
-       
+
+       /* Copy runtime surve data. */
+       obn->bev.first = obn->bev.last = NULL;
+       obn->path = NULL;
+
        return obn;
 }
 
@@ -1751,9 +1760,9 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
        unit_m4(mat);
        
        cu = par->data;
-       if (cu->path == NULL || cu->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
+       if (par->path == NULL || par->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
                BKE_displist_make_curveTypes(scene, par, 0);
-       if (cu->path == NULL) return;
+       if (par->path == NULL) return;
        
        /* catch exceptions: feature for nla stride editing */
        if (ob->ipoflag & OB_DISABLE_PATH) {
@@ -1784,7 +1793,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
        
        /* time calculus is correct, now apply distance offset */
        if (cu->flag & CU_OFFS_PATHDIST) {
-               ctime += timeoffs / cu->path->totdist;
+               ctime += timeoffs / par->path->totdist;
 
                /* restore */
                SWAP(float, sf_orig, ob->sf);
@@ -3135,8 +3144,9 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
        }
        else {
                ModifierData *md;
+               VirtualModifierData virtualModifierData;
                /* cloth */
-               for (md = modifiers_getVirtualModifierList(ob);
+               for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
                     md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
                     md = md->next)
                {
@@ -3157,10 +3167,11 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
 int BKE_object_is_deform_modified(Scene *scene, Object *ob)
 {
        ModifierData *md;
+       VirtualModifierData virtualModifierData;
        int flag = 0;
 
        /* cloth */
-       for (md = modifiers_getVirtualModifierList(ob);
+       for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
             md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
             md = md->next)
        {
@@ -3182,8 +3193,9 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
 bool BKE_object_is_animated(Scene *scene, Object *ob)
 {
        ModifierData *md;
+       VirtualModifierData virtualModifierData;
 
-       for (md = modifiers_getVirtualModifierList(ob); md; md = md->next)
+       for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next)
                if (modifier_dependsOnTime(md) &&
                    (modifier_isEnabled(scene, md, eModifierMode_Realtime) ||
                     modifier_isEnabled(scene, md, eModifierMode_Render)))
index bfec38419f18657f9c2e7f2678276df1cad9c76d..0294ff5645712f6d6c017a4f86e92819092a0d44 100644 (file)
@@ -73,6 +73,7 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot)
        GHash *gh;
        int i, step1 = 1;
        //int defbase_tot = BLI_countlist(&ob->defbase);
+       VirtualModifierData virtualModifierData;
 
        if (ob->defbase.first == NULL) {
                return NULL;
@@ -88,7 +89,7 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot)
        BLI_assert(BLI_ghash_size(gh) == defbase_tot);
 
        /* now loop through the armature modifiers and identify deform bones */
-       for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob) : md->next) {
+       for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob, &virtualModifierData) : md->next) {
                if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual)))
                        continue;
 
index 26563afa65b4441019014076409f94fa6d99266c..388201ba6b975a1e2b12c73e36d3c0a05a53d3c3 100644 (file)
@@ -57,6 +57,7 @@
 #include "BLI_callbacks.h"
 #include "BLI_string.h"
 #include "BLI_threads.h"
+#include "BLI_task.h"
 
 #include "BLF_translation.h"
 
@@ -1163,32 +1164,217 @@ 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)
+typedef struct ThreadedObjectUpdateState {
+       Scene *scene;
+       Scene *scene_parent;
+       SpinLock lock;
+} ThreadedObjectUpdateState;
+
+static void scene_update_object_add_task(void *node, void *user_data);
+
+static void scene_update_all_bases(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(scene_parent, object, scene->rigidbody_world);
+
+               if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
+                       BKE_group_handle_recalc_and_update(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)
+{
+#define PRINT if (G.debug & G_DEBUG) printf
+
+       ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool);
+       void *node = taskdata;
+       Object *object = DAG_threaded_update_get_node_object(node);
+       Scene *scene = state->scene;
+       Scene *scene_parent = state->scene_parent;
+
+       if (object) {
+               PRINT("Thread %d: update object %s\n", threadid, object->id.name);
+
+               /* 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(scene_parent, object, scene->rigidbody_world);
+       }
+       else {
+               PRINT("Threda %d: update node %s\n", threadid,
+                       DAG_threaded_update_get_node_name(node));
+       }
+
+       BLI_spin_lock(&state->lock);
+       /* 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);
+       BLI_spin_unlock(&state->lock);
+
+#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 scene_update_objects_threaded(Scene *scene, Scene *scene_parent)
+{
+       TaskScheduler *task_scheduler;
+       TaskPool *task_pool;
+       ThreadedObjectUpdateState state;
+       int tot_thread = BLI_system_thread_count();
+
+       if (tot_thread == 1) {
+               /* If only one thread is possible we don't bother self with
+                * task pool, which would be an overhead in cas e of single
+                * CPU core.
+                */
+               scene_update_all_bases(scene, scene_parent);
+               return;
+       }
+
+       /* Ensure malloc will go go fine from threads,
+        * this is needed because we could be in main thread here
+        * and malloc could be non-threda safe at this point because
+        * no other jobs are running.
+        */
+       BLI_begin_threaded_malloc();
+
+       /* XXX: Releasing DrawObject is not thread safe, but adding lock
+        *      around it is gonna to harm even more. So for now let's
+        *      free all caches from main thread.
+        *
+        * TODO(sergey): Making DrawObject thread-safe is a nice task on
+        *               it's own and it'll also make it possible to remove
+        *               this hack.
+        */
+       {
+               Base *base;
+               for (base = scene->base.first; base; base = base->next) {
+                       Object *ob = base->object;
+
+                       if (ob->recalc & OB_RECALC_ALL) {
+                               BKE_object_free_derived_caches(ob);
+                       }
+               }
+       }
+
+       state.scene = scene;
+       state.scene_parent = scene_parent;
+       BLI_spin_init(&state.lock);
+
+       task_scheduler = BLI_task_scheduler_create(tot_thread);
+       task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+       /* Initialize run-time data in the graph needed for traversing it
+        * from multiple threads.
+        *
+        * This will mark DAG nodes as object/non-object and will calculate
+        * "valency" of nodes (which is how many non-updated parents node
+        * have, which helps a lot checking whether node could be scheduled
+        * already or not).
+        */
+       DAG_threaded_update_begin(scene);
+
+       /* Put all nodes which are already ready for schedule to the task pool.
+        * usually its just a Scene node.
+        *
+        * We do lock here so no tthreads will start updating nodes valency
+        * while we're still fillign the queue in. Otherwise it's possible
+        * to run into situations when the same task is adding twice to the
+        * queue due to non-safe nature of function below.
+        */
+       BLI_spin_lock(&state.lock);
+       DAG_threaded_update_foreach_ready_node(scene, scene_update_object_add_task, task_pool);
+       BLI_spin_unlock(&state.lock);
+
+       /* work and wait until tasks are done */
+       BLI_task_pool_work_and_wait(task_pool);
+
+       /* free */
+       BLI_task_pool_free(task_pool);
+       BLI_task_scheduler_free(task_scheduler);
+
+       BLI_end_threaded_malloc();
+
+       BLI_spin_end(&state.lock);
+
+       /* XXX: Weak, very weak!
+        *
+        * We update dupligroups in single thread! :S
+        *
+        * This is because we've got absolutely no idea about dependencies
+        * inside the group and we only know order of objects in which we
+        * need to perform objects update.
+        *
+        * We even can not update different groups in different threads,
+        * because groups could share the objects and detecting whether
+        * object is updating in multiple threads is not so much easy.
+        *
+        * This is solvable with local group dependency graph or expanding
+        * current dependency graph to be aware of dependencies inside
+        * groups.
+        */
+       {
+               Base *base;
+               for (base = scene->base.first; base; base = base->next) {
+                       Object *object = base->object;
+
+                       if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
+                               BKE_group_handle_recalc_and_update(scene_parent, object, object->dup_group);
+               }
+       }
+}
+
+static void scene_update_objects(Scene *scene, Scene *scene_parent)
+{
+       Base *base;
+       int update_count = 0;
+
+       /* Optimization thing: don't do threads if no modifier
+        * stack need to be evaluated.
+        */
+       for (base = scene->base.first; base; base = base->next) {
+               Object *ob = base->object;
+
+               if (ob->recalc & OB_RECALC_ALL) {
+                       update_count++;
+               }
+       }
+
+       if (update_count > 1) {
+               scene_update_objects_threaded(scene, scene_parent);
+       }
+       else {
+               scene_update_all_bases(scene, scene_parent);
+       }
+}
+
+static void scene_update_tagged_recursive(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(bmain, scene->set, scene_parent);
+
+       /* scene objects */
+       scene_update_objects(scene, scene_parent);
+
        /* scene drivers... */
        scene_update_drivers(bmain, scene);
 
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
new file mode 100644 (file)
index 0000000..f57d428
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_TASK_H__
+#define __BLI_TASK_H__ 
+
+/** \file BLI_task.h
+ *  \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+/* Task Scheduler
+ * 
+ * Central scheduler that holds running threads ready to execute tasks. A single
+ * queue holds the task from all pools.
+ *
+ * Init/exit must be called before/after any task pools are created/freed, and
+ * must be called from the main threads. All other scheduler and pool functions
+ * are thread-safe. */
+
+typedef struct TaskScheduler TaskScheduler;
+
+enum {
+       TASK_SCHEDULER_AUTO_THREADS = 0,
+       TASK_SCHEDULER_SINGLE_THREAD = 1
+};
+
+TaskScheduler *BLI_task_scheduler_create(int num_threads);
+void BLI_task_scheduler_free(TaskScheduler *scheduler);
+
+int BLI_task_scheduler_num_threads(TaskScheduler *scheduler);
+
+/* Task Pool
+ *
+ * Pool of tasks that will be executed by the central TaskScheduler. For each
+ * pool, we can wait for all tasks to be done, or cancel them before they are
+ * done.
+ *
+ * Running tasks may spawn new tasks.
+ *
+ * Pools may be nested, i.e. a thread running a task can create another task
+ * pool with smaller tasks. When other threads are busy they will continue
+ * working on their own tasks, if not they will join in, no new threads will
+ * be launched.
+ */
+
+typedef enum TaskPriority {
+       TASK_PRIORITY_LOW,
+       TASK_PRIORITY_HIGH
+} TaskPriority;
+
+typedef struct TaskPool TaskPool;
+typedef void (*TaskRunFunction)(TaskPool *pool, void *taskdata, int threadid);
+
+TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
+void BLI_task_pool_free(TaskPool *pool);
+
+void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run,
+       void *taskdata, bool free_taskdata, TaskPriority priority);
+
+/* work and wait until all tasks are done */
+void BLI_task_pool_work_and_wait(TaskPool *pool);
+/* cancel all tasks, keep worker threads running */
+void BLI_task_pool_cancel(TaskPool *pool);
+/* stop all worker threads */
+void BLI_task_pool_stop(TaskPool *pool);
+
+/* for worker threads, test if cancelled */
+bool BLI_task_pool_cancelled(TaskPool *pool);
+
+/* optional userdata pointer to pass along to run function */
+void *BLI_task_pool_userdata(TaskPool *pool);
+
+/* optional mutex to use from run function */
+ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
+
+/* number of tasks done, for stats, don't use this to make decisions */
+size_t BLI_task_pool_tasks_done(TaskPool *pool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
index 331cac3ed7686e1e588dcbe6725cf35f07b6c635..a64745d1dfe3ea04a36e4419cb1742d1d836397d 100644 (file)
@@ -100,6 +100,7 @@ ThreadMutex *BLI_mutex_alloc(void);
 void BLI_mutex_free(ThreadMutex *mutex);
 
 void BLI_mutex_lock(ThreadMutex *mutex);
+bool BLI_mutex_trylock(ThreadMutex *mutex);
 void BLI_mutex_unlock(ThreadMutex *mutex);
 
 /* Spin Lock */
@@ -170,6 +171,16 @@ int BLI_thread_queue_size(ThreadQueue *queue);
 void BLI_thread_queue_wait_finish(ThreadQueue *queue);
 void BLI_thread_queue_nowait(ThreadQueue *queue);
 
+/* Condition */
+
+typedef pthread_cond_t ThreadCondition;
+
+void BLI_condition_init(ThreadCondition *cond);
+void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex);
+void BLI_condition_notify_one(ThreadCondition *cond);
+void BLI_condition_notify_all(ThreadCondition *cond);
+void BLI_condition_end(ThreadCondition *cond);
+
 #ifdef __cplusplus
 }
 #endif
index 1d94ca9afbca3a7cbfc9b5deaaa6476efd662266..3ae6e8f96564451b539ead86155591e52a9c5a67 100644 (file)
@@ -91,6 +91,7 @@ set(SRC
        intern/string.c
        intern/string_cursor_utf8.c
        intern/string_utf8.c
+       intern/task.c
        intern/threads.c
        intern/time.c
        intern/uvproject.c
@@ -150,6 +151,7 @@ set(SRC
        BLI_string_cursor_utf8.h
        BLI_string_utf8.h
        BLI_sys_types.h
+       BLI_task.h
        BLI_threads.h
        BLI_utildefines.h
        BLI_uvproject.h
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
new file mode 100644 (file)
index 0000000..63ea315
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+/* Types */
+
+typedef struct Task {
+       struct Task *next, *prev;
+
+       TaskRunFunction run;
+       void *taskdata;
+       bool free_taskdata;
+       TaskPool *pool;
+} Task;
+
+struct TaskPool {
+       TaskScheduler *scheduler;
+
+       volatile size_t num;
+       volatile size_t done;
+       ThreadMutex num_mutex;
+       ThreadCondition num_cond;
+
+       void *userdata;
+       ThreadMutex user_mutex;
+
+       volatile bool do_cancel;
+};
+
+struct TaskScheduler {
+       pthread_t *threads;
+       int num_threads;
+
+       ListBase queue;
+       ThreadMutex queue_mutex;
+       ThreadCondition queue_cond;
+
+       volatile bool do_exit;
+};
+
+typedef struct TaskThread {
+       TaskScheduler *scheduler;
+       int id;
+} TaskThread;
+
+/* Task Scheduler */
+
+static void task_pool_num_decrease(TaskPool *pool, size_t done)
+{
+       BLI_mutex_lock(&pool->num_mutex);
+       pool->num -= done;
+       pool->done += done;
+
+       BLI_assert(pool->num >= 0);
+       if(pool->num == 0)
+               BLI_condition_notify_all(&pool->num_cond);
+
+       BLI_mutex_unlock(&pool->num_mutex);
+}
+
+static void task_pool_num_increase(TaskPool *pool)
+{
+       BLI_mutex_lock(&pool->num_mutex);
+
+       pool->num++;
+       BLI_condition_notify_all(&pool->num_cond);
+
+       BLI_mutex_unlock(&pool->num_mutex);
+}
+
+static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task)
+{
+       BLI_mutex_lock(&scheduler->queue_mutex);
+
+       while(!scheduler->queue.first && !scheduler->do_exit)
+               BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
+
+       if(!scheduler->queue.first) {
+               BLI_mutex_unlock(&scheduler->queue_mutex);
+               BLI_assert(scheduler->do_exit);
+               return false;
+       }
+       
+       *task = scheduler->queue.first;
+       BLI_remlink(&scheduler->queue, *task);
+
+       BLI_mutex_unlock(&scheduler->queue_mutex);
+
+       return true;
+}
+
+static void *task_scheduler_thread_run(void *thread_p)
+{
+       TaskThread *thread = (TaskThread*)thread_p;
+       TaskScheduler *scheduler = thread->scheduler;
+       int thread_id = thread->id;
+       Task *task;
+
+       /* keep popping off tasks */
+       while(task_scheduler_thread_wait_pop(scheduler, &task)) {
+               /* run task */
+               task->run(task->pool, task->taskdata, thread_id);
+
+               /* notify pool task was done */
+               task_pool_num_decrease(task->pool, 1);
+
+               /* delete task */
+               if(task->free_taskdata)
+                       MEM_freeN(task->taskdata);
+               MEM_freeN(task);
+       }
+
+       MEM_freeN(thread);
+
+       return NULL;
+}
+
+TaskScheduler *BLI_task_scheduler_create(int num_threads)
+{
+       TaskScheduler *scheduler = MEM_callocN(sizeof(TaskScheduler), "TaskScheduler");
+
+       /* multiple places can use this task scheduler, sharing the same
+        * threads, so we keep track of the number of users. */
+       scheduler->do_exit = false;
+
+       scheduler->queue.first = scheduler->queue.last = NULL;
+       BLI_mutex_init(&scheduler->queue_mutex);
+       BLI_condition_init(&scheduler->queue_cond);
+
+       if(num_threads == 0) {
+               /* automatic number of threads will be main thread + num cores */
+               num_threads = BLI_system_thread_count();
+       }
+
+       /* main thread will also work, so we count it too */
+       num_threads -= 1;
+
+       /* launch threads that will be waiting for work */
+       if(num_threads > 0) {
+               int i;
+
+               scheduler->num_threads = num_threads;
+               scheduler->threads = MEM_callocN(sizeof(pthread_t)*num_threads, "TaskScheduler threads");
+
+               for(i = 0; i < num_threads; i++) {
+                       TaskThread *thread = MEM_callocN(sizeof(TaskThread), "TaskThread");
+                       thread->scheduler = scheduler;
+                       thread->id = i+1;
+
+                       if(pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
+                               fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
+                               MEM_freeN(thread);
+                       }
+               }
+       }
+       
+       return scheduler;
+}
+
+void BLI_task_scheduler_free(TaskScheduler *scheduler)
+{
+       Task *task;
+
+       /* stop all waiting threads */
+       BLI_mutex_lock(&scheduler->queue_mutex);
+       scheduler->do_exit = true;
+       BLI_condition_notify_all(&scheduler->queue_cond);
+       BLI_mutex_unlock(&scheduler->queue_mutex);
+
+       /* delete threads */
+       if(scheduler->threads) {
+               int i;
+
+               for(i = 0; i < scheduler->num_threads; i++) {
+                       if(pthread_join(scheduler->threads[i], NULL) != 0)
+                               fprintf(stderr, "TaskScheduler failed to join thread %d/%d\n", i, scheduler->num_threads);
+               }
+
+               MEM_freeN(scheduler->threads);
+       }
+
+       /* delete leftover tasks */
+       for(task = scheduler->queue.first; task; task = task->next)
+               if(task->free_taskdata)
+                       MEM_freeN(task->taskdata);
+       BLI_freelistN(&scheduler->queue);
+
+       /* delete mutex/condition */
+       BLI_mutex_end(&scheduler->queue_mutex);
+       BLI_condition_end(&scheduler->queue_cond);
+
+       MEM_freeN(scheduler);
+}
+
+int BLI_task_scheduler_num_threads(TaskScheduler *scheduler)
+{
+       return scheduler->num_threads + 1;
+}
+
+static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority)
+{
+       task_pool_num_increase(task->pool);
+
+       /* add task to queue */
+       BLI_mutex_lock(&scheduler->queue_mutex);
+
+       if(priority == TASK_PRIORITY_HIGH)
+               BLI_addhead(&scheduler->queue, task);
+       else
+               BLI_addtail(&scheduler->queue, task);
+
+       BLI_condition_notify_one(&scheduler->queue_cond);
+       BLI_mutex_unlock(&scheduler->queue_mutex);
+}
+
+static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
+{
+       Task *task, *nexttask;
+       size_t done = 0;
+
+       BLI_mutex_lock(&scheduler->queue_mutex);
+
+       /* free all tasks from this pool from the queue */
+       for(task = scheduler->queue.first; task; task = nexttask) {
+               nexttask = task->next;
+
+               if(task->pool == pool) {
+                       if(task->free_taskdata)
+                               MEM_freeN(task->taskdata);
+                       BLI_freelinkN(&scheduler->queue, task);
+
+                       done++;
+               }
+       }
+
+       BLI_mutex_unlock(&scheduler->queue_mutex);
+
+       /* notify done */
+       task_pool_num_decrease(pool, done);
+}
+
+/* Task Pool */
+
+TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
+{
+       TaskPool *pool = MEM_callocN(sizeof(TaskPool), "TaskPool");
+
+       pool->scheduler = scheduler;
+       pool->num = 0;
+       pool->do_cancel = false;
+
+       BLI_mutex_init(&pool->num_mutex);
+       BLI_condition_init(&pool->num_cond);
+
+       pool->userdata = userdata;
+       BLI_mutex_init(&pool->user_mutex);
+
+       return pool;
+}
+
+void BLI_task_pool_free(TaskPool *pool)
+{
+       BLI_task_pool_stop(pool);
+
+       BLI_mutex_end(&pool->num_mutex);
+       BLI_condition_end(&pool->num_cond);
+
+       BLI_mutex_end(&pool->user_mutex);
+
+       MEM_freeN(pool);
+}
+
+void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run,
+       void *taskdata, bool free_taskdata, TaskPriority priority)
+{
+       Task *task = MEM_callocN(sizeof(Task), "Task");
+
+       task->run = run;
+       task->taskdata = taskdata;
+       task->free_taskdata = free_taskdata;
+       task->pool = pool;
+
+       task_scheduler_push(pool->scheduler, task, priority);
+}
+
+void BLI_task_pool_work_and_wait(TaskPool *pool)
+{
+       TaskScheduler *scheduler = pool->scheduler;
+
+       BLI_mutex_lock(&pool->num_mutex);
+
+       while(pool->num != 0) {
+               Task *task, *work_task = NULL;
+               bool found_task = false;
+
+               BLI_mutex_unlock(&pool->num_mutex);
+
+               BLI_mutex_lock(&scheduler->queue_mutex);
+
+               /* find task from this pool. if we get a task from another pool,
+                * we can get into deadlock */
+
+               for(task = scheduler->queue.first; task; task = task->next) {
+                       if(task->pool == pool) {
+                               work_task = task;
+                               found_task = true;
+                               BLI_remlink(&scheduler->queue, task);
+                               break;
+                       }
+               }
+
+               BLI_mutex_unlock(&scheduler->queue_mutex);
+
+               /* if found task, do it, otherwise wait until other tasks are done */
+               if(found_task) {
+                       /* run task */
+                       work_task->run(pool, work_task->taskdata, 0);
+
+                       /* delete task */
+                       if(work_task->free_taskdata)
+                               MEM_freeN(work_task->taskdata);
+                       MEM_freeN(work_task);
+
+                       /* notify pool task was done */
+                       task_pool_num_decrease(pool, 1);
+               }
+
+               BLI_mutex_lock(&pool->num_mutex);
+               if(pool->num == 0)
+                       break;
+
+               if(!found_task)
+                       BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
+       }
+
+       BLI_mutex_unlock(&pool->num_mutex);
+}
+
+void BLI_task_pool_cancel(TaskPool *pool)
+{
+       pool->do_cancel = true;
+
+       task_scheduler_clear(pool->scheduler, pool);
+
+       /* wait until all entries are cleared */
+       BLI_mutex_lock(&pool->num_mutex);
+       while(pool->num)
+               BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
+       BLI_mutex_unlock(&pool->num_mutex);
+
+       pool->do_cancel = false;
+}
+
+void BLI_task_pool_stop(TaskPool *pool)
+{
+       task_scheduler_clear(pool->scheduler, pool);
+
+       BLI_assert(pool->num == 0);
+}
+
+bool BLI_task_pool_cancelled(TaskPool *pool)
+{
+       return pool->do_cancel;
+}
+
+void *BLI_task_pool_userdata(TaskPool *pool)
+{
+       return pool->userdata;
+}
+
+ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
+{
+       return &pool->user_mutex;
+}
+
+size_t BLI_task_pool_tasks_done(TaskPool *pool)
+{
+       return pool->done;
+}
+
index e0ea3bbf685afbf5a44edeedb043fc3a5b51b7de..cd3132682b6e05c5f02e7fffb6b04e4fcc03f3b9 100644 (file)
@@ -412,6 +412,11 @@ void BLI_mutex_unlock(ThreadMutex *mutex)
        pthread_mutex_unlock(mutex);
 }
 
+bool BLI_mutex_trylock(ThreadMutex *mutex)
+{
+       return (pthread_mutex_trylock(mutex) == 0);
+}
+
 void BLI_mutex_end(ThreadMutex *mutex)
 {
        pthread_mutex_destroy(mutex);
@@ -772,6 +777,32 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
        pthread_mutex_unlock(&queue->mutex);
 }
 
+/* Condition */
+void BLI_condition_init(ThreadCondition *cond)
+{
+       pthread_cond_init(cond, NULL);
+}
+
+void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
+{
+       pthread_cond_wait(cond, mutex);
+}
+
+void BLI_condition_notify_one(ThreadCondition *cond)
+{
+       pthread_cond_signal(cond);
+}
+
+void BLI_condition_notify_all(ThreadCondition *cond)
+{
+       pthread_cond_broadcast(cond);
+}
+
+void BLI_condition_end(ThreadCondition *cond)
+{
+       pthread_cond_destroy(cond);
+}
+
 /* ************************************************ */
 
 void BLI_begin_threaded_malloc(void)
index 5d30bf6ff738cfa315e7cee25ef897d6e465df15..d78edc80654a9a241880bc99d4031d00db50a0f6 100644 (file)
@@ -3391,11 +3391,8 @@ static void direct_link_curve(FileData *fd, Curve *cu)
                if (cu->wordspace == 0.0f) cu->wordspace = 1.0f;
        }
 
-       cu->bev.first = cu->bev.last = NULL;
-       cu->disp.first = cu->disp.last = NULL;
        cu->editnurb = NULL;
        cu->lastsel = NULL;
-       cu->path = NULL;
        cu->editfont = NULL;
        
        for (nu = cu->nurb.first; nu; nu = nu->next) {
@@ -5017,6 +5014,10 @@ static void direct_link_object(FileData *fd, Object *ob)
        ob->gpulamp.first= ob->gpulamp.last = NULL;
        link_list(fd, &ob->pc_ids);
 
+       /* Runtime curve data  */
+       ob->bev.first = ob->bev.last = NULL;
+       ob->path = NULL;
+
        /* in case this value changes in future, clamp else we get undefined behavior */
        CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
 
@@ -5519,6 +5520,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
        wm->winactive = NULL;
        wm->initialized = 0;
        wm->op_undo_depth = 0;
+       wm->is_interface_locked = 0;
 }
 
 static void lib_link_windowmanager(FileData *fd, Main *main)
index 57392c60f809f2e20f9474532bf387e0ec61f9e3..699da98225a2435c187bd6e5b85bb15f47236a45 100644 (file)
@@ -1,4 +1,5 @@
 /*
+
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -1017,6 +1018,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
        Scene *scene = CTX_data_scene(C);
        Object *ob;
        ModifierData *md, *vmd;
+       VirtualModifierData virtualModifierData;
        int i, lastCageIndex, cageIndex;
 
        /* verify we have valid data */
@@ -1039,7 +1041,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
        cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
 
        /* XXX virtual modifiers are not accesible for python */
-       vmd = modifiers_getVirtualModifierList(ob);
+       vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        for (i = 0; vmd; i++, vmd = vmd->next) {
                if (md == vmd)
index 09138a5523aeeaf0a767d02bbfb2f88dca80b231..563f416ead0bc84799d2e4988caa7cc5dda529c5 100644 (file)
@@ -273,6 +273,7 @@ typedef struct RenderJob {
        short *do_update;
        float *progress;
        ReportList *reports;
+       bool interface_locked;
 } RenderJob;
 
 static void render_freejob(void *rjv)
@@ -498,6 +499,15 @@ static void render_endjob(void *rjv)
 
                BKE_image_release_ibuf(ima, ibuf, lock);
        }
+
+       /* Finally unlock the user interface (if it was locked). */
+       if (rj->interface_locked) {
+               /* Interface was locked, so window manager couldn't have been changed
+                * and using one from Global will unlock exactly the same manager as
+                * was locked before running the job.
+                */
+               WM_set_locked_interface(G.main->wm.first, false);
+       }
 }
 
 /* called by render, check job 'stop' value or the global */
@@ -523,10 +533,14 @@ static int render_break(void *UNUSED(rjv))
 
 /* runs in thread, no cursor setting here works. careful with notifiers too (malloc conflicts) */
 /* maybe need a way to get job send notifer? */
-static void render_drawlock(void *UNUSED(rjv), int lock)
+static void render_drawlock(void *rjv, int lock)
 {
-       BKE_spacedata_draw_locks(lock);
-       
+       RenderJob *rj = rjv;
+
+       /* If interface is locked, renderer callback shall do nothing. */
+       if (!rj->interface_locked) {
+               BKE_spacedata_draw_locks(lock);
+       }
 }
 
 /* catch esc */
@@ -649,6 +663,23 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
                        rj->lay |= v3d->localvd->lay;
        }
 
+       /* Lock the user interface depending on render settings. */
+       if (scene->r.use_lock_interface) {
+               WM_set_locked_interface(CTX_wm_manager(C), true);
+
+               /* Set flag interface need to be unlocked.
+                *
+                * This is so because we don't have copy of render settings
+                * accessible from render job and copy is needed in case
+                * of non-locked rendering, so we wouldn't try to unlock
+                * anything if option was initially unset but then was
+                * enabled during rendering.
+                */
+               rj->interface_locked = true;
+
+               /* TODO(sergey): clean memory used by viewport? */
+       }
+
        /* setup job */
        if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render";
        else name = "Render";
index 8e2a29964ee4f6e7b4459680db7693ace8ac23a4..79fab72b770dd491fcca12526fb9c90daa5a089b 100644 (file)
@@ -150,6 +150,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
 {
        Mesh *me = (Mesh *)ob->data;
        ModifierData *md;
+       VirtualModifierData virtualModifierData;
 
        if (ob->sculpt && ob->sculpt->bm) {
                /* can't combine multires and dynamic topology */
@@ -161,7 +162,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
                return NULL;
        }
 
-       for (md = modifiers_getVirtualModifierList(ob); md; md = md->next) {
+       for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
                if (md->type == eModifierType_Multires) {
                        MultiresModifierData *mmd = (MultiresModifierData *)md;
 
@@ -180,8 +181,9 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
 static int sculpt_has_active_modifiers(Scene *scene, Object *ob)
 {
        ModifierData *md;
+       VirtualModifierData virtualModifierData;
 
-       md = modifiers_getVirtualModifierList(ob);
+       md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        /* exception for shape keys because we can edit those */
        for (; md; md = md->next) {
@@ -198,6 +200,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
        ModifierData *md;
        Mesh *me = (Mesh *)ob->data;
        MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
+       VirtualModifierData virtualModifierData;
 
        if (mmd || ob->sculpt->bm)
                return 0;
@@ -206,7 +209,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
        if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
                return 1;
 
-       md = modifiers_getVirtualModifierList(ob);
+       md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        /* exception for shape keys because we can edit those */
        for (; md; md = md->next) {
index 20bbfbbf343b8b01d8de23a51121cb6dce71c91c..a845f8e525c33fa57ff9b992563786506c7427f7 100644 (file)
@@ -360,7 +360,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
        ot->poll = space_image_main_area_poll;
 
        /* flags */
-       ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+       ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_ALLOW_LOCKED;
        
        /* properties */
        RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -575,7 +575,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
        ot->poll = space_image_main_area_poll;
 
        /* flags */
-       ot->flag = OPTYPE_BLOCKING;
+       ot->flag = OPTYPE_BLOCKING | OPTYPE_ALLOW_LOCKED;
        
        /* properties */
        RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX,
@@ -638,6 +638,9 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
        
        /* api callbacks */
        ot->invoke = image_view_ndof_invoke;
+
+       /* flags */
+       ot->flag = OPTYPE_ALLOW_LOCKED;
 }
 
 /********************** view all operator *********************/
@@ -693,6 +696,9 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
        /* api callbacks */
        ot->exec = image_view_all_exec;
        ot->poll = space_image_main_area_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_GRAB_POINTER;
 }
 
 /********************** view selected operator *********************/
@@ -755,6 +761,9 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
        /* api callbacks */
        ot->exec = image_view_selected_exec;
        ot->poll = image_view_selected_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_GRAB_POINTER;
 }
 
 /********************** view zoom in/out operator *********************/
@@ -797,6 +806,9 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
        ot->exec = image_view_zoom_in_exec;
        ot->poll = space_image_main_area_poll;
 
+       /* flags */
+       ot->flag = OPTYPE_ALLOW_LOCKED;
+
        /* properties */
        RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
 }
@@ -839,6 +851,9 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
        ot->exec = image_view_zoom_out_exec;
        ot->poll = space_image_main_area_poll;
 
+       /* flags */
+       ot->flag = OPTYPE_ALLOW_LOCKED;
+
        /* properties */
        RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
 }
@@ -880,7 +895,10 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
        /* api callbacks */
        ot->exec = image_view_zoom_ratio_exec;
        ot->poll = space_image_main_area_poll;
-       
+
+       /* flags */
+       ot->flag = OPTYPE_ALLOW_LOCKED;
+
        /* 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);
index 9ab6336ab0e7cb31df1293681b74f87606b2eac8..512651e91fbee8a403847b4ba0c756a7169d33fa 100644 (file)
@@ -5554,7 +5554,7 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
        if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
 
                UI_ThemeColor(TH_WIRE_EDIT);
-               for (bl = cu->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) {
+               for (bl = ob->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) {
                        BevPoint *bevp = (BevPoint *)(bl + 1);
                        int nr = bl->nr;
                        int skip = nu->resolu / 16;
@@ -5977,7 +5977,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
        }
        else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
                Curve *cu = ob->data;
-               if ((cu->flag & CU_PATH) && cu->path && cu->path->data) {
+               if ((cu->flag & CU_PATH) && ob->path && ob->path->data) {
                        float mindist, guidevec1[4], guidevec2[3];
 
                        //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
@@ -6235,7 +6235,6 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
        glDepthMask(0);
        
        if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
-               Curve *cu = ob->data;
                DerivedMesh *dm = ob->derivedFinal;
                bool has_faces = false;
 
@@ -6246,7 +6245,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                        has_faces = BKE_displist_has_faces(&ob->disp);
                }
 
-               if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) {
+               if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) {
                        draw_index_wire = false;
                        if (dm) {
                                draw_mesh_object_outline(v3d, ob, dm);
@@ -6287,8 +6286,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign
                glDepthMask(0);  /* disable write in zbuffer, selected edge wires show better */
 
                if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
-                       Curve *cu = ob->data;
-                       if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) {
+                       if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) {
                                if (ob->type == OB_CURVE)
                                        draw_index_wire = false;
 
@@ -6719,7 +6717,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
                                        draw_bounding_volume(scene, ob, ob->boundtype);
                                }
                        }
-                       else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) {
+                       else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) {
                                empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
                        }
 
@@ -6737,7 +6735,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
                                        draw_bounding_volume(scene, ob, ob->boundtype);
                                }
                        }
-                       else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) {
+                       else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) {
                                empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
 
 //XXX old animsys                              if (cu->path)
index ea3687ad7157e5ae878074534440f23a68abbb63..1f9ef5f5bc5588a94d39c273e4e98260c652b3c5 100644 (file)
@@ -259,11 +259,12 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em
        int i, a, numleft = 0, numVerts = 0;
        int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
        float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+       VirtualModifierData virtualModifierData;
 
        modifiers_clearErrors(ob);
 
        dm = NULL;
-       md = modifiers_getVirtualModifierList(ob);
+       md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        /* compute the deformation matrices and coordinates for the first
         * modifiers with on cage editing that are enabled and support computing
@@ -313,6 +314,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma
        MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
        int has_multires = mmd != NULL && mmd->sculptlvl > 0;
        int numleft = 0;
+       VirtualModifierData virtualModifierData;
 
        if (has_multires) {
                *deformmats = NULL;
@@ -321,7 +323,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma
        }
 
        dm = NULL;
-       md = modifiers_getVirtualModifierList(ob);
+       md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 
        for (; md; md = md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -374,7 +376,8 @@ void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3
                float (*origVerts)[3] = MEM_dupallocN(deformedVerts);
                float *quats = NULL;
                int i, deformed = 0;
-               ModifierData *md = modifiers_getVirtualModifierList(ob);
+               VirtualModifierData virtualModifierData;
+               ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
                Mesh *me = (Mesh *)ob->data;
 
                for (; md; md = md->next) {
index deb9902c35d073c694419ffe0bfac564b5fdbd51..437229d63a85de02b3181b25f6911f29439b508a 100644 (file)
@@ -177,18 +177,14 @@ typedef struct Curve {
        struct BoundBox *bb;
        
        ListBase nurb;          /* actual data, called splines in rna */
-       ListBase disp;          /* undeformed display list, used mostly for texture space calculation */
        
        EditNurb *editnurb;     /* edited data, not in file, use pointer so we can check for it */
        
        struct Object *bevobj, *taperobj, *textoncurve;
        struct Ipo *ipo    DNA_DEPRECATED;  /* old animation system, deprecated for 2.5 */
-       Path *path;
        struct Key *key;
        struct Material **mat;
        
-       ListBase bev;
-       
        /* texture space, copied as one block in editobject.c */
        float loc[3];
        float size[3];
index de34f101c3155c11a1eb44c0632f95314371560a..4544e0332c4b4ca4d7d7967f5d333838f989bbb9 100644 (file)
@@ -276,6 +276,9 @@ typedef struct Object {
        struct RigidBodyCon *rigidbody_constraint;      /* settings for Bullet constraint */
 
        float ima_ofs[2];               /* offset for image empties */
+
+       struct Path *path;
+       ListBase bev;
 } Object;
 
 /* Warning, this is not used anymore because hooks are now modifiers */
index 5e877ed697b35a43cb0dee974d7c1847a61b867c..ac38578b981b8e1b9907d9c661860352405385e2 100644 (file)
@@ -428,7 +428,8 @@ typedef struct RenderData {
         * Render to image editor, fullscreen or to new window.
         */
        short displaymode;
-       short pad7;
+       char use_lock_interface;
+       char pad7;
 
        /**
         * Flags for render settings. Use bit-masking to access the settings.
index 27aef3b8ec63715969d37b88dfa05bdc4dd999d8..29fac36ddd078030b854496a8c44a605704b2474 100644 (file)
@@ -151,6 +151,9 @@ typedef struct wmWindowManager {
 
        ListBase timers;                                        /* active timers */
        struct wmTimer *autosavetimer;          /* timer for auto save */
+
+       char is_interface_locked;               /* indicates whether interface is locked for user interaction */
+       char par[7];
 } wmWindowManager;
 
 /* wmWindowManager.initialized */
index d46b1a2843945ae1769a0881904d98f0c705796e..cb6ba0f85d0400d24b3ed7a10f06256ed221ea89 100644 (file)
@@ -4520,7 +4520,12 @@ 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, "use_lock_interface", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "use_lock_interface", 1);
+       RNA_def_property_ui_text(prop, "Lock Interface", "Lock interface during rendering in favor of giving more memory to the renderer");
+       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",
index e09fa18ffc5ff85a53d24f676a78475264788031..0a61777ee672fe7a8b40372583305bd4246af93a 100644 (file)
@@ -387,12 +387,12 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
                        BKE_object_to_mat3(amd->curve_ob, tmp_mat);
                        scale = mat3_to_scale(tmp_mat);
                                
-                       if (!cu->path) {
+                       if (!amd->curve_ob->path) {
                                cu->flag |= CU_PATH; // needed for path & bevlist
                                BKE_displist_make_curveTypes(scene, amd->curve_ob, 0);
                        }
-                       if (cu->path)
-                               length = scale * cu->path->totdist;
+                       if (amd->curve_ob->path)
+                               length = scale * amd->curve_ob->path->totdist;
                }
        }
 
index 72b54e2f1f7359fea668a6806b75f583e8de34e4..fb9b8b8f10b37bca5477137bc8ffa38d3fd15310 100644 (file)
@@ -412,6 +412,9 @@ void        WM_main_playanim(int argc, const char **argv);
 /* debugging only, convenience function to write on crash */
 int write_crash_blend(void);
 
+                       /* Lock the interface for any communication */
+void        WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+
 #ifdef __cplusplus
 }
 #endif
index f1932c8aa97f2bbb6a205482150c2403765d581d..2364c4b13bb71ad78f53d54732224d1093275400 100644 (file)
@@ -133,6 +133,7 @@ struct ImBuf;
                                                                 * and don't make sense to be accessed from the
                                                                 * search menu, even if poll() returns TRUE.
                                                                 * currently only used for the search toolbox */
+#define OPTYPE_ALLOW_LOCKED    128     /* Allow operator to run when interface is locked */
 
 /* context to call operator in for WM_operator_name_call */
 /* rna_ui.c contains EnumPropertyItem's of these, keep in sync */
index e57baf8801be26115f9e676925ce9b57c8608bf6..0ed6e64346326f760529a2126e3a1663d625f311 100644 (file)
@@ -1441,6 +1441,22 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
        }
 }
 
+/* Check whether operator is allowed to run in case interface is locked,
+ * If interface is unlocked, will always return truth.
+ */
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
+{
+       wmWindowManager *wm = CTX_wm_manager(C);
+
+       if (wm->is_interface_locked) {
+               if ((ot->flag & OPTYPE_ALLOW_LOCKED) == 0) {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 /* bad hacking event system... better restore event type for checking of KM_CLICK for example */
 /* XXX modal maps could use different method (ton) */
 static void wm_event_modalmap_end(wmEvent *event)
@@ -1467,7 +1483,12 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                wmOperator *op = handler->op;
                wmOperatorType *ot = op->type;
 
-               if (ot->modal) {
+               if (!wm_operator_check_locked_interface(C, ot)) {
+                       /* Interface is locked and pperator is not allowed to run,
+                        * nothing to do in this case.
+                        */
+               }
+               else if (ot->modal) {
                        /* we set context to where modal handler came from */
                        wmWindowManager *wm = CTX_wm_manager(C);
                        ScrArea *area = CTX_wm_area(C);
@@ -1539,7 +1560,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
 
                if (ot) {
-                       retval = wm_operator_invoke(C, ot, event, properties, NULL, FALSE);
+                       if (wm_operator_check_locked_interface(C, ot)) {
+                               retval = wm_operator_invoke(C, ot, event, properties, NULL, FALSE);
+                       }
                }
        }
        /* Finished and pass through flag as handled */
@@ -1745,7 +1768,11 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
                /* comment this out to flood the console! (if you really want to test) */
                !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
                ;
+#    define PRINT if (do_debug_handler) printf
+#else
+#  define PRINT(format, ...)
 #endif
+
        wmWindowManager *wm = CTX_wm_manager(C);
        wmEventHandler *handler, *nexthandler;
        int action = WM_HANDLER_CONTINUE;
@@ -1781,28 +1808,16 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
                                wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
                                wmKeyMapItem *kmi;
 
-#ifndef NDEBUG
-                               if (do_debug_handler) {
-                                       printf("%s:   checking '%s' ...", __func__, keymap->idname);
-                               }
-#endif
+                               PRINT("%s:   checking '%s' ...", __func__, keymap->idname);
 
                                if (!keymap->poll || keymap->poll(C)) {
 
-#ifndef NDEBUG
-                                       if (do_debug_handler) {
-                                               printf("pass\n");
-                                       }
-#endif
+                                       PRINT("pass\n");
 
                                        for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
                                                if (wm_eventmatch(event, kmi)) {
 
-#ifndef NDEBUG
-                                                       if (do_debug_handler) {
-                                                               printf("%s:     item matched '%s'\n", __func__, kmi->idname);
-                                                       }
-#endif
+                                                       PRINT("%s:     item matched '%s'\n", __func__, kmi->idname);
 
                                                        /* weak, but allows interactive callback to not use rawkey */
                                                        event->keymap_idname = kmi->idname;
@@ -1821,32 +1836,28 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
                                                                        if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
                                                                                printf("%s:       handled - and pass on! '%s'\n", __func__, kmi->idname);
                                                                
-#ifndef NDEBUG
-                                                               if (do_debug_handler) {
-                                                                       printf("%s:       un-handled '%s'...", __func__, kmi->idname);
-                                                               }
-#endif
+                                                                       PRINT("%s:       un-handled '%s'...", __func__, kmi->idname);
                                                        }
                                                }
                                        }
                                }
                                else {
-#ifndef NDEBUG
-                                       if (do_debug_handler) {
-                                               printf("fail\n");
-                                       }
-#endif
+                                       PRINT("fail\n");
                                }
                        }
                        else if (handler->ui_handle) {
-                               action |= wm_handler_ui_call(C, handler, event, always_pass);
+                               if (!wm->is_interface_locked) {
+                                       action |= wm_handler_ui_call(C, handler, event, always_pass);
+                               }
                        }
                        else if (handler->type == WM_HANDLER_FILESELECT) {
-                               /* screen context changes here */
-                               action |= wm_handler_fileselect_call(C, handlers, handler, event);
+                               if (!wm->is_interface_locked) {
+                                       /* screen context changes here */
+                                       action |= wm_handler_fileselect_call(C, handlers, handler, event);
+                               }
                        }
                        else if (handler->dropboxes) {
-                               if (event->type == EVT_DROP) {
+                               if (!wm->is_interface_locked && event->type == EVT_DROP) {
                                        wmDropBox *drop = handler->dropboxes->first;
                                        for (; drop; drop = drop->next) {
                                                /* other drop custom types allowed */
@@ -1912,6 +1923,8 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
        if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL))
                wm_cursor_arrow_move(CTX_wm_window(C), event);
 
+#undef PRINT
+
        return action;
 }
 
@@ -3221,3 +3234,24 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
        WM_event_print(&event);
 #endif
 }
+
+void WM_set_locked_interface(wmWindowManager *wm, bool lock)
+{
+       /* This will prevent events from being handled while interface is locked
+        *
+        * Use a "local" flag for now, because currently no other areas could
+        * benefit of locked interface anyway (aka using G.is_interface_locked
+        * wouldn't be useful anywhere outside of window manager, so let's not
+        * pollute global context with such an information for now).
+        */
+       wm->is_interface_locked = lock ? 1 : 0;
+
+       /* This will prevent drawing regions which uses non-threadsafe data.
+        * Currently it'll be just a 3D viewport.
+        *
+        * TODO(sergey): Make it different locked states, so different jobs
+        *               could lock different areas of blender and allow
+        *               interation with others?
+        */
+       BKE_spacedata_draw_locks(lock);
+}
index 84d235308002026f0071e4ee78965d79a7587cbf..bbc9d818b566153e209d93333bd0212422cebc14 100644 (file)
@@ -92,6 +92,7 @@
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_material.h"
+#include "BKE_modifier.h"
 #include "BKE_packedFile.h"
 #include "BKE_scene.h"
 #include "BKE_node.h"
@@ -1517,6 +1518,7 @@ int main(int argc, const char **argv)
 
        IMB_init();
        BKE_images_init();
+       BKE_modifier_init();
 
        BKE_brush_system_init();
 
index 2c642d4bd0484ba849182de950e553412fbdddd1..69137bc7842ea1ac34aea88ee4635df2f87479e6 100644 (file)
@@ -64,6 +64,7 @@ extern "C"
 #include "BKE_node.h"
 #include "BKE_report.h"
 #include "BKE_library.h"
+#include "BKE_modifier.h"
 #include "BLI_threads.h"
 #include "BLI_blenlib.h"
 #include "DNA_scene_types.h"
@@ -448,6 +449,7 @@ int main(int argc, char** argv)
 
        IMB_init();
        BKE_images_init();
+       BKE_modifier_init();
 
 #ifdef WITH_FFMPEG
        IMB_ffmpeg_init();