Made curves almost thread-safe
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 3 Jul 2013 12:32:42 +0000 (12:32 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 3 Jul 2013 12:32:42 +0000 (12:32 +0000)
Now modifier stack wouldn't modify original curve's nurbs
and will operate on a copy of nurbs.

This makes it possible to process curve object update with
shared curve datablocks from multiple threads. There's no
big overhead for creating a copy of nurbs comparing to old
behavior which was allocating original vertex array and
apply coordinates on curve after all modifier are applied.

The only remained issue with curves is curve's bounding box
and texture space. It's not thread-safe, but it wouldn't
lead to crashes -- it just could lead to either memory
leak or wrong texture coordinates due to difference in
modifiers stacks of objects which shares the same curve.

source/blender/blenkernel/BKE_anim.h
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/displist.c

index 539c5780cd51ace7cd09ee131f20232217ff288e..7de7a745ed638f57ad1e95f33ca5454de2f0c23c 100644 (file)
@@ -59,7 +59,7 @@ void animviz_calc_motionpaths(struct Scene *scene, ListBase *targets);
 /* Curve Paths */
 
 void free_path(struct Path *path);
-void calc_curvepath(struct Object *ob);
+void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
 int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight);
 
 /* ---------------------------------------------------- */
index 6d3a7054dfe7e4b6723d0f329206c21a2eb379a3..de60e1447dd44a64d29c49b99f444b421ea629bf 100644 (file)
@@ -93,7 +93,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, bool for_render);
+void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, 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 23655f04ccc4bf51e8bc66f36c1897bf97cbb21d..290e3ee5433111a7986114990136c9f789192a3c 100644 (file)
@@ -488,7 +488,7 @@ void free_path(Path *path)
 /* calculate a curve-deform path for a curve 
  *  - only called from displist.c -> do_makeDispListCurveTypes
  */
-void calc_curvepath(Object *ob)
+void calc_curvepath(Object *ob, ListBase *nurbs)
 {
        BevList *bl;
        BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
@@ -499,7 +499,6 @@ void calc_curvepath(Object *ob)
        float *fp, *dist, *maxdist, xyz[3];
        float fac, d = 0, fac1, fac2;
        int a, tot, cycl = 0;
-       ListBase *nurbs;
        
        /* in a path vertices are with equal differences: path->len = number of verts */
        /* NOW WITH BEVELCURVE!!! */
@@ -518,7 +517,6 @@ void calc_curvepath(Object *ob)
                return;
        }
 
-       nurbs = BKE_curve_nurbs_get(cu);
        nu = nurbs->first;
 
        ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
index fd3f61b25d1a4ddcd5265203b0c1b9a6ce043630..8950a8c72e6c932c30870f5e2a4b15d0464fd4ca 100644 (file)
@@ -2239,7 +2239,7 @@ static void make_bevel_list_2D(BevList *bl)
        }
 }
 
-void BKE_curve_bevelList_make(Object *ob, bool for_render)
+void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
 {
        /*
         * - convert all curves to polys, with indication of resol and flags for double-vertices
@@ -2271,14 +2271,10 @@ void BKE_curve_bevelList_make(Object *ob, bool for_render)
        /* STEP 1: MAKE POLYS  */
 
        BLI_freelistN(&(ob->curve_cache->bev));
+       nu = nurbs->first;
        if (cu->editnurb && ob->type != OB_FONT) {
-               ListBase *nurbs = BKE_curve_editNurbs_get(cu);
-               nu = nurbs->first;
                is_editmode = 1;
        }
-       else {
-               nu = cu->nurb.first;
-       }
 
        for (; nu; nu = nu->next) {
                
index a74a48382a1bb048a0ff25a9b90bb7d1d7584ea9..ddccb2fa783a0c194810bd37d74f7765895ded83 100644 (file)
@@ -45,7 +45,6 @@
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
 #include "BLI_scanfill.h"
-#include "BLI_threads.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_global.h"
@@ -781,19 +780,16 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, int re
        return pretessellatePoint;
 }
 
-static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, int renderResolution,
-                                     float (**originalVerts_r)[3],
-                                     float (**deformedVerts_r)[3], int *numVerts_r)
+static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
+                                     int forRender, int renderResolution)
 {
        VirtualModifierData virtualModifierData;
        ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        Curve *cu = ob->data;
-       ListBase *nurb = BKE_curve_nurbs_get(cu);
        int numVerts = 0;
        const int editmode = (!forRender && (cu->editnurb || cu->editfont));
        ModifierApplyFlag app_flag = 0;
-       float (*originalVerts)[3] = NULL;
        float (*deformedVerts)[3] = NULL;
        float *keyVerts = NULL;
        int required_mode;
@@ -821,7 +817,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in
                         * this is also the reason curves do not use a virtual
                         * shape key modifier yet. */
                        deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts);
-                       originalVerts = MEM_dupallocN(deformedVerts);
                        BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts);
                }
        }
@@ -839,7 +834,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in
 
                        if (!deformedVerts) {
                                deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
-                               originalVerts = MEM_dupallocN(deformedVerts);
                        }
 
                        mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag);
@@ -849,17 +843,15 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in
                }
        }
 
-       if (deformedVerts)
+       if (deformedVerts) {
                BK_curve_nurbs_vertexCos_apply(nurb, deformedVerts);
+               MEM_freeN(deformedVerts);
+       }
        if (keyVerts) /* these are not passed through modifier stack */
                BKE_curve_nurbs_keyVertexTilts_apply(nurb, keyVerts);
 
        if (keyVerts)
                MEM_freeN(keyVerts);
-
-       *originalVerts_r = originalVerts;
-       *deformedVerts_r = deformedVerts;
-       *numVerts_r = numVerts;
 }
 
 static float (*displist_get_allverts(ListBase *dispbase, int *totvert))[3]
@@ -896,15 +888,14 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3])
        }
 }
 
-static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal,
-                                      int forRender, int renderResolution,
-                                      float (*originalVerts)[3], float (*deformedVerts)[3])
+static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
+                                      ListBase *dispbase, DerivedMesh **derivedFinal,
+                                      int forRender, int renderResolution)
 {
        VirtualModifierData virtualModifierData;
        ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        ModifierData *pretessellatePoint;
        Curve *cu = ob->data;
-       ListBase *nurb = BKE_curve_nurbs_get(cu);
        int required_mode = 0, totvert = 0;
        int editmode = (!forRender && (cu->editnurb || cu->editfont));
        DerivedMesh *dm = NULL, *ndm;
@@ -1049,12 +1040,6 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
                }
                (*derivedFinal) = dm;
        }
-
-       if (deformedVerts) {
-               BK_curve_nurbs_vertexCos_apply(nurb, originalVerts);
-               MEM_freeN(originalVerts);
-               MEM_freeN(deformedVerts);
-       }
 }
 
 static void displist_surf_indices(DispList *dl)
@@ -1204,25 +1189,24 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *derivedFina
 void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
                             DerivedMesh **derivedFinal, int forRender, int forOrco, int renderResolution)
 {
-       ListBase *nubase;
+       ListBase nubase = {NULL, NULL};
        Nurb *nu;
        Curve *cu = ob->data;
        DispList *dl;
        float *data;
        int len;
-       int numVerts;
-       float (*originalVerts)[3];
-       float (*deformedVerts)[3];
 
-       if (!forRender && cu->editnurb)
-               nubase = BKE_curve_editNurbs_get(cu);
-       else
-               nubase = &cu->nurb;
+       if (!forRender && cu->editnurb) {
+               BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu));
+       }
+       else {
+               BKE_nurbList_duplicate(&nubase, &cu->nurb);
+       }
 
        if (!forOrco)
-               curve_calc_modifiers_pre(scene, ob, forRender, renderResolution, &originalVerts, &deformedVerts, &numVerts);
+               curve_calc_modifiers_pre(scene, ob, &nubase, forRender, renderResolution);
 
-       for (nu = nubase->first; nu; nu = nu->next) {
+       for (nu = nubase.first; nu; nu = nu->next) {
                if (forRender || nu->hide == 0) {
                        int resolu = nu->resolu, resolv = nu->resolv;
 
@@ -1286,6 +1270,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
        }
 
        /* Calculate curve's boundig box from non-modified display list. */
+       /* TODO(sergey): not thread-safe. */
        if (cu->bb == NULL) {
                cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
        }
@@ -1296,10 +1281,11 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
        }
 
        if (!forOrco) {
-               curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal,
-                                         forRender, renderResolution,
-                                         originalVerts, deformedVerts);
+               curve_calc_modifiers_post(scene, ob, &nubase, dispbase, derivedFinal,
+                                         forRender, renderResolution);
        }
+
+       BKE_nurbList_free(&nubase);
 }
 
 static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **data_r)
@@ -1393,15 +1379,9 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
        }
        else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
                ListBase dlbev;
-               ListBase *nubase;
-               float (*originalVerts)[3];
-               float (*deformedVerts)[3];
-               int numVerts;
-
-               nubase = BKE_curve_nurbs_get(cu);
+               ListBase nubase = {NULL, NULL};
 
-               /* XXX: Temp workaround for depsgraph_mt branch. */
-               BLI_lock_thread(LOCK_CUSTOM1);
+               BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(cu));
 
                BLI_freelistN(&(ob->curve_cache->bev));
 
@@ -1412,21 +1392,21 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                        BKE_vfont_to_curve(G.main, scene, ob, 0);
 
                if (!forOrco)
-                       curve_calc_modifiers_pre(scene, ob, forRender, renderResolution, &originalVerts, &deformedVerts, &numVerts);
+                       curve_calc_modifiers_pre(scene, ob, &nubase, forRender, renderResolution);
 
-               BKE_curve_bevelList_make(ob, forRender != FALSE);
+               BKE_curve_bevelList_make(ob, &nubase, forRender != FALSE);
 
                /* If curve has no bevel will return nothing */
                BKE_curve_bevel_make(scene, ob, &dlbev, forRender, renderResolution);
 
                /* no bevel or extrude, and no width correction? */
                if (!dlbev.first && cu->width == 1.0f) {
-                       curve_to_displist(cu, nubase, dispbase, forRender, renderResolution);
+                       curve_to_displist(cu, &nubase, dispbase, forRender, renderResolution);
                }
                else {
                        float widfac = cu->width - 1.0f;
                        BevList *bl = ob->curve_cache->bev.first;
-                       Nurb *nu = nubase->first;
+                       Nurb *nu = nubase.first;
 
                        for (; bl && nu; bl = bl->next, nu = nu->next) {
                                DispList *dl;
@@ -1593,13 +1573,14 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
                }
 
                if (!(cu->flag & CU_DEFORM_FILL)) {
-                       curve_to_filledpoly(cu, nubase, dispbase);
+                       curve_to_filledpoly(cu, &nubase, dispbase);
                }
 
                if ((cu->flag & CU_PATH) && !forOrco)
-                       calc_curvepath(ob);
+                       calc_curvepath(ob, &nubase);
 
                /* Calculate curve's boundig box from non-modified display list. */
+               /* TODO(sergey): not thread-safe. */
                if (cu->bb == NULL) {
                        cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
                }
@@ -1611,14 +1592,13 @@ 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);
+                       curve_calc_modifiers_post(scene, ob, &nubase, dispbase, derivedFinal, forRender, renderResolution);
 
                if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
-                       curve_to_filledpoly(cu, nubase, dispbase);
+                       curve_to_filledpoly(cu, &nubase, dispbase);
                }
+
+               BKE_nurbList_free(&nubase);
        }
 }