Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 11 Jan 2018 14:14:30 +0000 (15:14 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 11 Jan 2018 14:14:30 +0000 (15:14 +0100)
1  2 
source/blender/blenkernel/intern/mesh_evaluate.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/depsgraph/intern/eval/deg_eval.cc
source/blender/depsgraph/intern/eval/deg_eval_flush.cc
source/blender/modifiers/intern/MOD_meshdeform.c

index f25b6ed41c78d89f1a7e6d592c5094d283eedf95,76c629912acac58fabcb93efe07c0fdaca31b7e5..4e03155ea6c92cd8b2bbe15c57d4add7fb0995a3
@@@ -287,12 -287,11 +287,11 @@@ void BKE_mesh_calc_normals_poly
          int numLoops, int numPolys, float (*r_polynors)[3],
          const bool only_face_normals)
  {
-       const bool do_threaded = (numPolys > BKE_MESH_OMP_LIMIT);
        float (*pnors)[3] = r_polynors;
  
        ParallelRangeSettings settings;
        BLI_parallel_range_settings_defaults(&settings);
-       settings.use_threading = do_threaded;
+       settings.min_iter_per_thread = 1024;
  
        if (only_face_normals) {
                BLI_assert((pnors != NULL) || (numPolys == 0));
@@@ -1702,6 -1701,152 +1701,6 @@@ void BKE_mesh_normals_loop_to_vertex
  /** \} */
  
  
 -/* -------------------------------------------------------------------- */
 -
 -/** \name Mesh Tangent Calculations
 - * \{ */
 -
 -/* Tangent space utils. */
 -
 -/* User data. */
 -typedef struct {
 -      const MPoly *mpolys;   /* faces */
 -      const MLoop *mloops;   /* faces's vertices */
 -      const MVert *mverts;   /* vertices */
 -      const MLoopUV *luvs;   /* texture coordinates */
 -      float (*lnors)[3];     /* loops' normals */
 -      float (*tangents)[4];  /* output tangents */
 -      int num_polys;         /* number of polygons */
 -} BKEMeshToTangent;
 -
 -/* Mikktspace's API */
 -static int get_num_faces(const SMikkTSpaceContext *pContext)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      return p_mesh->num_polys;
 -}
 -
 -static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      return p_mesh->mpolys[face_idx].totloop;
 -}
 -
 -static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
 -      copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
 -}
 -
 -static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
 -                                   const int vert_idx)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
 -}
 -
 -static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
 -}
 -
 -static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
 -                       const int face_idx, const int vert_idx)
 -{
 -      BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
 -      float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
 -      copy_v3_v3(p_res, fv_tangent);
 -      p_res[3] = face_sign;
 -}
 -
 -/**
 - * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
 - * split normals can be used to recreate the full tangent space.
 - * Note: * The mesh should be made of only tris and quads!
 - */
 -void BKE_mesh_loop_tangents_ex(
 -        const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
 -        float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
 -        const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
 -        ReportList *reports)
 -{
 -      BKEMeshToTangent mesh_to_tangent = {NULL};
 -      SMikkTSpaceContext s_context = {NULL};
 -      SMikkTSpaceInterface s_interface = {NULL};
 -
 -      const MPoly *mp;
 -      int mp_index;
 -
 -      /* First check we do have a tris/quads only mesh. */
 -      for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
 -              if (mp->totloop > 4) {
 -                      BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
 -                      return;
 -              }
 -      }
 -
 -      /* Compute Mikktspace's tangent normals. */
 -      mesh_to_tangent.mpolys = mpolys;
 -      mesh_to_tangent.mloops = mloops;
 -      mesh_to_tangent.mverts = mverts;
 -      mesh_to_tangent.luvs = loopuvs;
 -      mesh_to_tangent.lnors = loopnors;
 -      mesh_to_tangent.tangents = r_looptangent;
 -      mesh_to_tangent.num_polys = numPolys;
 -
 -      s_context.m_pUserData = &mesh_to_tangent;
 -      s_context.m_pInterface = &s_interface;
 -      s_interface.m_getNumFaces = get_num_faces;
 -      s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
 -      s_interface.m_getPosition = get_position;
 -      s_interface.m_getTexCoord = get_texture_coordinate;
 -      s_interface.m_getNormal = get_normal;
 -      s_interface.m_setTSpaceBasic = set_tspace;
 -
 -      /* 0 if failed */
 -      if (genTangSpaceDefault(&s_context) == false) {
 -              BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
 -      }
 -}
 -
 -/**
 - * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
 - * \note
 - * - There must be a valid loop's CD_NORMALS available.
 - * - The mesh should be made of only tris and quads!
 - */
 -void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
 -{
 -      MLoopUV *loopuvs;
 -      float (*loopnors)[3];
 -
 -      /* Check we have valid texture coordinates first! */
 -      if (uvmap) {
 -              loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
 -      }
 -      else {
 -              loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
 -      }
 -      if (!loopuvs) {
 -              BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
 -              return;
 -      }
 -
 -      loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
 -      if (!loopnors) {
 -              BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
 -              return;
 -      }
 -
 -      BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
 -                                loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
 -}
 -
 -/** \} */
 -
 -
  /* -------------------------------------------------------------------- */
  
  /** \name Polygon Calculations
@@@ -2274,12 -2419,12 +2273,12 @@@ void BKE_mesh_calc_volume
   */
  void BKE_mesh_loops_to_mface_corners(
          CustomData *fdata, CustomData *ldata,
 -        CustomData *pdata, unsigned int lindex[4], int findex,
 -        const int polyindex,
 +        CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
 +        const int UNUSED(polyindex),
          const int mf_len, /* 3 or 4 */
  
          /* cache values to avoid lookups every time */
 -        const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */
 +        const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
          const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
          const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
          const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
  )
  {
        MTFace *texface;
 -      MTexPoly *texpoly;
        MCol *mcol;
        MLoopCol *mloopcol;
        MLoopUV *mloopuv;
        int i, j;
  
 -      for (i = 0; i < numTex; i++) {
 +      for (i = 0; i < numUV; i++) {
                texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
 -              texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
 -
 -              ME_MTEXFACE_CPY(texface, texpoly);
  
                for (j = 0; j < mf_len; j++) {
                        mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
   *
   * \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
   */
 -void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface,
 +void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface,
                                  int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
  {
        /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
         *       Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
         *       this. Better imho to live with it for now. :/ --mont29
         */
 -      const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
 +      const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
        const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
        const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
        const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
        const int *pidx;
        unsigned int (*lidx)[4];
  
 -      for (i = 0; i < numTex; i++) {
 +      for (i = 0; i < numUV; i++) {
                MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
 -              MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i);
                MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
  
                for (findex = 0, pidx = polyindices, lidx = loopindices;
                     findex < num_faces;
                     pidx++, lidx++, findex++, texface++)
                {
 -                      ME_MTEXFACE_CPY(texface, &texpoly[*pidx]);
 -
                        for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
                                copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
                        }
@@@ -2692,7 -2844,7 +2691,7 @@@ int BKE_mesh_recalc_tessellation
        /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
         * they are directly tessellated from */
        CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
 -      CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
 +      CustomData_from_bmeshpoly(fdata, ldata, totface);
  
        if (do_face_nor_copy) {
                /* If polys have a normals layer, copying that to faces can help
         * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
         * ...
         */
 -      BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface);
 +      BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
  
        /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
         * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
@@@ -2892,7 -3044,7 +2891,7 @@@ int BKE_mesh_mpoly_to_mface(struct Cust
        MPoly *mp, *mpoly;
        MFace *mface, *mf;
  
 -      const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
 +      const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
        const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
        const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
        const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
  
        CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
  
 -      CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
 +      CustomData_from_bmeshpoly(fdata, ldata, totface);
  
        mp = mpoly;
        k = 0;
                                mf->v2 = mloop[mf->v2].v;
                                mf->v3 = mloop[mf->v3].v;
  
 -                              BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
 -                                                              lindex, k, i, 3,
 -                                                              numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
 +                              BKE_mesh_loops_to_mface_corners(
 +                                      fdata, ldata, pdata,
 +                                      lindex, k, i, 3,
 +                                      numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
                                test_index_face(mf, fdata, k, 3);
                        }
                        else {
                                mf->v3 = mloop[mf->v3].v;
                                mf->v4 = mloop[mf->v4].v;
  
 -                              BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
 -                                                              lindex, k, i, 4,
 -                                                              numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
 +                              BKE_mesh_loops_to_mface_corners(
 +                                      fdata, ldata, pdata,
 +                                      lindex, k, i, 4,
 +                                      numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
                                test_index_face(mf, fdata, k, 4);
                        }
  
  #endif /* USE_BMESH_SAVE_AS_COMPAT */
  
  
 -static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
 -                                   MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
 +static void bm_corners_to_loops_ex(
 +        ID *id, CustomData *fdata, CustomData *ldata,
 +        MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
  {
        MTFace *texface;
 -      MTexPoly *texpoly;
        MCol *mcol;
        MLoopCol *mloopcol;
        MLoopUV *mloopuv;
  
        for (i = 0; i < numTex; i++) {
                texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
 -              texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i);
 -
 -              ME_MTEXFACE_CPY(texpoly, texface);
  
                mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
                copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
@@@ -3115,7 -3268,7 +3114,7 @@@ void BKE_mesh_do_versions_convert_mface
                                             mesh->medge, mesh->mface,
                                             &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
  
 -      CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata);
 +      CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
  
        BKE_mesh_update_customdata_pointers(mesh, true);
  }
@@@ -3158,7 -3311,7 +3157,7 @@@ void BKE_mesh_convert_mfaces_to_mpolys_
  
        CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
  
 -      CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly);
 +      CustomData_to_bmeshpoly(fdata, ldata, totloop);
  
        if (id) {
                /* ensure external data is transferred */
  
  #       undef ML
  
 -              bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol);
 +              bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
  
                if (polyindex) {
                        *polyindex = i;
index 24bcd4c84767b1e31f7fe367621232eed8376b2e,1b174cf46542d75750a1129aff342bc684be2390..84b82ed53bb1ab8a5ce8852f1d41e620f17b19f2
@@@ -58,6 -58,7 +58,7 @@@
  #include "BLI_edgehash.h"
  #include "BLI_math.h"
  #include "BLI_memarena.h"
+ #include "BLI_task.h"
  #include "BLI_threads.h"
  
  #include "BKE_pbvh.h"
@@@ -1476,19 -1477,70 +1477,70 @@@ static void ccgDM_copyFinalFaceArray(De
        }
  }
  
+ typedef struct CopyFinalLoopArrayData {
+       CCGDerivedMesh *ccgdm;
+       MLoop *mloop;
+       int grid_size;
+       int *grid_offset;
+       int edge_size;
+       size_t mloop_index;
+ } CopyFinalLoopArrayData;
+ static void copyFinalLoopArray_task_cb(
+         void *__restrict userdata,
+         const int iter,
+         const ParallelRangeTLS *__restrict UNUSED(tls))
+ {
+       CopyFinalLoopArrayData *data = userdata;
+       CCGDerivedMesh *ccgdm = data->ccgdm;
+       CCGSubSurf *ss = ccgdm->ss;
+       const int grid_size = data->grid_size;
+       const int edge_size = data->edge_size;
+       CCGFace *f = ccgdm->faceMap[iter].face;
+       const int num_verts = ccgSubSurf_getFaceNumVerts(f);
+       const int grid_index = data->grid_offset[iter];
+       const size_t loop_index = 4 * (size_t)grid_index * (grid_size - 1) * (grid_size - 1);
+       MLoop *ml = &data->mloop[loop_index];
+       for (int S = 0; S < num_verts; S++) {
+               for (int y = 0; y < grid_size - 1; y++) {
+                       for (int x = 0; x < grid_size - 1; x++) {
+                               uint v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+                                                      edge_size, grid_size);
+                               uint v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+                                                      edge_size, grid_size);
+                               uint v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+                                                      edge_size, grid_size);
+                               uint v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+                                                      edge_size, grid_size);
+                               ml->v = v1;
+                               ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
+                               ml++;
+                               ml->v = v2;
+                               ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
+                               ml++;
+                               ml->v = v3;
+                               ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
+                               ml++;
+                               ml->v = v4;
+                               ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
+                               ml++;
+                       }
+               }
+       }
+ }
  static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
  {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
        CCGSubSurf *ss = ccgdm->ss;
-       int index;
-       int totface;
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-       MLoop *ml;
-       /* DMFlagMat *faceFlags = ccgdm->faceFlags; */ /* UNUSED */
  
        if (!ccgdm->ehash) {
-               BLI_rw_mutex_lock(&ccgdm->loops_cache_rwlock, THREAD_LOCK_WRITE);
+               BLI_mutex_lock(&ccgdm->loops_cache_lock);
                if (!ccgdm->ehash) {
                        MEdge *medge;
                        EdgeHash *ehash;
  
                        atomic_cas_ptr((void**)&ccgdm->ehash, ccgdm->ehash, ehash);
                }
-               BLI_rw_mutex_unlock(&ccgdm->loops_cache_rwlock);
+               BLI_mutex_unlock(&ccgdm->loops_cache_lock);
        }
  
-       BLI_rw_mutex_lock(&ccgdm->loops_cache_rwlock, THREAD_LOCK_READ);
-       totface = ccgSubSurf_getNumFaces(ss);
-       ml = mloop;
-       for (index = 0; index < totface; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
-               int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               /* int flag = (faceFlags) ? faceFlags[index * 2]: ME_SMOOTH; */ /* UNUSED */
-               /* int mat_nr = (faceFlags) ? faceFlags[index * 2 + 1]: 0; */ /* UNUSED */
-               for (S = 0; S < numVerts; S++) {
-                       for (y = 0; y < gridSize - 1; y++) {
-                               for (x = 0; x < gridSize - 1; x++) {
-                                       unsigned int v1, v2, v3, v4;
-                                       v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
-                                                         edgeSize, gridSize);
-                                       v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
-                                                         edgeSize, gridSize);
-                                       v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
-                                                         edgeSize, gridSize);
-                                       v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
-                                                         edgeSize, gridSize);
+       CopyFinalLoopArrayData data;
+       data.ccgdm = ccgdm;
+       data.mloop = mloop;
+       data.grid_size = ccgSubSurf_getGridSize(ss);
+       data.grid_offset = dm->getGridOffset(dm);
+       data.edge_size = ccgSubSurf_getEdgeSize(ss);
  
-                                       ml->v = v1;
-                                       ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
-                                       ml++;
-                                       ml->v = v2;
-                                       ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
-                                       ml++;
+       /* NOTE: For a dense subdivision we've got enough work for each face and
+        * hence can dedicate whole thread to single face. For less dense
+        * subdivision we handle multiple faces per thread.
+        */
+       data.mloop_index = data.grid_size >= 5 ? 1 : 8;
  
-                                       ml->v = v3;
-                                       ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
-                                       ml++;
+       ParallelRangeSettings settings;
+       BLI_parallel_range_settings_defaults(&settings);
+       settings.min_iter_per_thread = 1;
  
-                                       ml->v = v4;
-                                       ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
-                                       ml++;
-                               }
-                       }
-               }
-       }
-       BLI_rw_mutex_unlock(&ccgdm->loops_cache_rwlock);
+       BLI_task_parallel_range(0, ccgSubSurf_getNumFaces(ss),
+                               &data,
+                               copyFinalLoopArray_task_cb,
+                               &settings);
  }
  
  static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly)
@@@ -1902,8 -1931,7 +1931,8 @@@ static void ccgDM_glNormalFast(float *a
        no[1] = b_dZ * a_cX - b_dX * a_cZ;
        no[2] = b_dX * a_cY - b_dY * a_cX;
  
 -      /* don't normalize, GL_NORMALIZE is enabled */
 +      normalize_v3(no); /* we no longer rely on GL_NORMALIZE */
 +
        glNormal3fv(no);
  }
  
@@@ -3411,6 -3439,261 +3440,6 @@@ static void ccgDM_drawMappedFacesMat(De
  #undef PASSATTRIB
  }
  
 -static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
 -                                      DMSetDrawOptionsTex drawParams,
 -                                      DMSetDrawOptionsMappedTex drawParamsMapped,
 -                                      DMCompareDrawOptions compareDrawOptions,
 -                                      void *userData, DMDrawFlag flag)
 -{
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 -      CCGKey key;
 -      int colType;
 -      const MLoopCol *mloopcol = NULL;
 -      MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
 -      DMFlagMat *faceFlags = ccgdm->faceFlags;
 -      DMDrawOption draw_option;
 -      int i, totpoly;
 -      bool flush;
 -      const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
 -      const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
 -      unsigned int next_actualFace;
 -      unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
 -      int mat_index;
 -      int tot_element, start_element, tot_drawn;
 -
 -      if (use_colors) {
 -              colType = CD_TEXTURE_MLOOPCOL;
 -              mloopcol = dm->getLoopDataArray(dm, colType);
 -              if (!mloopcol) {
 -                      colType = CD_PREVIEW_MLOOPCOL;
 -                      mloopcol = dm->getLoopDataArray(dm, colType);
 -              }
 -              if (!mloopcol) {
 -                      colType = CD_MLOOPCOL;
 -                      mloopcol = dm->getLoopDataArray(dm, colType);
 -              }
 -      }
 -
 -#ifdef WITH_OPENSUBDIV
 -      if (ccgdm->useGpuBackend) {
 -              const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
 -              if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
 -                      return;
 -              }
 -              if (drawParams == NULL) {
 -                      ccgSubSurf_drawGLMesh(ss, true, -1, -1);
 -                      return;
 -              }
 -              const int level = ccgSubSurf_getSubdivisionLevels(ss);
 -              const int face_side = 1 << level;
 -              const int grid_side = 1 << (level - 1);
 -              const int face_patches = face_side * face_side;
 -              const int grid_patches = grid_side * grid_side;
 -              const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
 -              int current_patch = 0;
 -              int mat_nr = -1;
 -              int start_draw_patch = 0, num_draw_patches = 0;
 -              bool draw_smooth = false;
 -              for (i = 0; i < num_base_faces; ++i) {
 -                      const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
 -                      const int num_patches = (num_face_verts == 4) ? face_patches
 -                                                                    : num_face_verts * grid_patches;
 -                      if (faceFlags) {
 -                              mat_nr = faceFlags[i].mat_nr;
 -                              draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
 -                      }
 -                      else {
 -                              mat_nr = 0;
 -                              draw_smooth = false;
 -                      }
 -
 -                      if (drawParams != NULL) {
 -                              MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
 -                              draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
 -                      }
 -                      else {
 -                              draw_option = (drawParamsMapped)
 -                                                ? drawParamsMapped(userData, i, mat_nr)
 -                                                : DM_DRAW_OPTION_NORMAL;
 -                      }
 -
 -                      flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
 -
 -                      const int next_face = min_ii(i + 1, num_base_faces - 1);
 -                      if (!flush && compareDrawOptions) {
 -                              flush |= compareDrawOptions(userData, i, next_face) == 0;
 -                      }
 -                      if (!flush && faceFlags) {
 -                              bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
 -                              flush |= (new_draw_smooth != draw_smooth);
 -                      }
 -
 -                      current_patch += num_patches;
 -
 -                      if (flush) {
 -                              if (draw_option != DM_DRAW_OPTION_SKIP) {
 -                                      num_draw_patches += num_patches;
 -                              }
 -                              if (num_draw_patches != 0) {
 -                                      glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
 -                                      ccgSubSurf_drawGLMesh(ss,
 -                                                            true,
 -                                                            start_draw_patch,
 -                                                            num_draw_patches);
 -                              }
 -                              start_draw_patch = current_patch;
 -                              num_draw_patches = 0;
 -                      }
 -                      else {
 -                              num_draw_patches += num_patches;
 -                      }
 -              }
 -              glShadeModel(GL_SMOOTH);
 -              return;
 -      }
 -#endif
 -
 -      CCG_key_top_level(&key, ss);
 -      ccgdm_pbvh_update(ccgdm);
 -
 -      GPU_vertex_setup(dm);
 -      GPU_normal_setup(dm);
 -      GPU_triangle_setup(dm);
 -      if (flag & DM_DRAW_USE_TEXPAINT_UV)
 -              GPU_texpaint_uv_setup(dm);
 -      else
 -              GPU_uv_setup(dm);
 -      if (mloopcol) {
 -              GPU_color_setup(dm, colType);
 -      }
 -
 -      next_actualFace = 0;
 -
 -      /* lastFlag = 0; */ /* UNUSED */
 -      for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
 -              GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
 -              next_actualFace = bufmat->polys[0];
 -              totpoly = bufmat->totpolys;
 -
 -              tot_element = 0;
 -              tot_drawn = 0;
 -              start_element = 0;
 -
 -              for (i = 0; i < totpoly; i++) {
 -                      int polyindex = bufmat->polys[i];
 -                      CCGFace *f = ccgdm->faceMap[polyindex].face;
 -                      int numVerts = ccgSubSurf_getFaceNumVerts(f);
 -                      int index = ccgDM_getFaceMapIndex(ss, f);
 -                      int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
 -                      int mat_nr;
 -                      int facequads = numVerts * gridFaces * gridFaces;
 -                      int actualFace = ccgdm->faceMap[polyindex].startFace;
 -
 -                      if (i != totpoly - 1) {
 -                              polyindex = bufmat->polys[i + 1];
 -                              next_actualFace = ccgdm->faceMap[polyindex].startFace;
 -                      }
 -
 -                      if (faceFlags) {
 -                              mat_nr = faceFlags[orig_index].mat_nr;
 -                      }
 -                      else {
 -                              mat_nr = 0;
 -                      }
 -
 -                      if (drawParams) {
 -                              MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL;
 -                              draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
 -                      }
 -                      else if (index != ORIGINDEX_NONE)
 -                              draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
 -                      else
 -                              draw_option = DM_DRAW_OPTION_NORMAL;
 -
 -                      /* flush buffer if current triangle isn't drawable or it's last triangle */
 -                      flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
 -
 -                      if (!flush && compareDrawOptions) {
 -                              /* also compare draw options and flush buffer if they're different
 -                               * need for face selection highlight in edit mode */
 -                              flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
 -                      }
 -
 -                      tot_element += facequads * 6;
 -
 -                      if (flush) {
 -                              if (draw_option != DM_DRAW_OPTION_SKIP)
 -                                      tot_drawn += facequads * 6;
 -
 -                              if (tot_drawn) {
 -                                      if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
 -                                              GPU_color_switch(1);
 -                                      else
 -                                              GPU_color_switch(0);
 -
 -                                      GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
 -                                      tot_drawn = 0;
 -                              }
 -
 -                              start_element = tot_element;
 -                      }
 -                      else {
 -                              tot_drawn += facequads * 6;
 -                      }
 -              }
 -      }
 -
 -
 -      GPU_buffers_unbind();
 -}
 -
 -static void ccgDM_drawFacesTex(DerivedMesh *dm,
 -                               DMSetDrawOptionsTex setDrawOptions,
 -                               DMCompareDrawOptions compareDrawOptions,
 -                               void *userData, DMDrawFlag flag)
 -{
 -      ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
 -}
 -
 -static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
 -                                     DMSetDrawOptionsMappedTex setDrawOptions,
 -                                     DMCompareDrawOptions compareDrawOptions,
 -                                     void *userData, DMDrawFlag flag)
 -{
 -      ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
 -}
 -
 -/* same as cdDM_drawUVEdges */
 -static void ccgDM_drawUVEdges(DerivedMesh *dm)
 -{
 -      MPoly *mpoly = dm->getPolyArray(dm);
 -      int totpoly = dm->getNumPolys(dm);
 -      int prevstart = 0;
 -      bool prevdraw = true;
 -      int curpos = 0;
 -      int i;
 -
 -      GPU_uvedge_setup(dm);
 -      for (i = 0; i < totpoly; i++, mpoly++) {
 -              const bool draw = (mpoly->flag & ME_HIDE) == 0;
 -
 -              if (prevdraw != draw) {
 -                      if (prevdraw && (curpos != prevstart)) {
 -                              glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
 -                      }
 -                      prevstart = curpos;
 -              }
 -
 -              curpos += 2 * mpoly->totloop;
 -              prevdraw = draw;
 -      }
 -      if (prevdraw && (curpos != prevstart)) {
 -              glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
 -      }
 -      GPU_buffers_unbind();
 -}
 -
  static void ccgDM_drawMappedFaces(DerivedMesh *dm,
                                    DMSetDrawOptions setDrawOptions,
                                    DMSetMaterial setMaterial,
@@@ -3796,7 -4079,7 +3825,7 @@@ static void ccgDM_release(DerivedMesh *
                        MEM_freeN(ccgdm->faceMap);
                }
  
-               BLI_rw_mutex_end(&ccgdm->loops_cache_rwlock);
+               BLI_mutex_end(&ccgdm->loops_cache_lock);
                BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
  
                MEM_freeN(ccgdm);
@@@ -4343,10 -4626,13 +4372,10 @@@ static void set_default_ccgdm_callbacks
        ccgdm->dm.drawEdges = ccgDM_drawEdges;
        ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
        ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
 -      ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
        ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
        ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
 -      ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
        ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
        ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
 -      ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
  
        ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
        ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
@@@ -4787,7 -5073,7 +4816,7 @@@ static CCGDerivedMesh *getCCGDerivedMes
        ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4;
        ccgdm->dm.numTessFaceData = 0;
  
-       BLI_rw_mutex_init(&ccgdm->loops_cache_rwlock);
+       BLI_mutex_init(&ccgdm->loops_cache_lock);
        BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock);
  
        return ccgdm;
@@@ -4804,7 -5090,8 +4833,7 @@@ static bool subsurf_use_gpu_backend(Sub
         */
        return
                (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
 -              (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
 -              (openSubdiv_supportGPUDisplay());
 +              (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
  #else
        (void)flags;
        return false;
index 116f853ebdf988f73dc801d259fb03e8f38c5b97,c29a0708cef949ff02303469b0861d2e64bbeeb4..a6c6a16a52803732972353de8dab34a4e8d81010
  #include "BLI_task.h"
  #include "BLI_ghash.h"
  
 -extern "C" {
 -#include "BKE_depsgraph.h"
 -#include "BKE_global.h"
 -} /* extern "C" */
 +#include "DNA_object_types.h"
  
  #include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
  
  #include "atomic_ops.h"
  
@@@ -66,11 -68,13 +66,11 @@@ namespace DEG 
  static void schedule_children(TaskPool *pool,
                                Depsgraph *graph,
                                OperationDepsNode *node,
 -                              const unsigned int layers,
                                const int thread_id);
  
  struct DepsgraphEvalState {
        EvaluationContext *eval_ctx;
        Depsgraph *graph;
 -      unsigned int layers;
        bool do_stats;
  };
  
@@@ -94,12 -98,13 +94,12 @@@ static void deg_task_run_func(TaskPool 
        }
        /* Schedule children. */
        BLI_task_pool_delayed_push_begin(pool, thread_id);
 -      schedule_children(pool, state->graph, node, state->layers, thread_id);
 +      schedule_children(pool, state->graph, node, thread_id);
        BLI_task_pool_delayed_push_end(pool, thread_id);
  }
  
  typedef struct CalculatePengindData {
        Depsgraph *graph;
 -      unsigned int layers;
  } CalculatePengindData;
  
  static void calculate_pending_func(
  {
        CalculatePengindData *data = (CalculatePengindData *)data_v;
        Depsgraph *graph = data->graph;
 -      unsigned int layers = data->layers;
        OperationDepsNode *node = graph->operations[i];
 -      IDDepsNode *id_node = node->owner->owner;
  
        node->num_links_pending = 0;
        node->scheduled = false;
  
        /* count number of inputs that need updates */
 -      if ((id_node->layers & layers) != 0 &&
 -          (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
 -      {
 +      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                foreach (DepsRelation *rel, node->inlinks) {
                        if (rel->from->type == DEG_NODE_TYPE_OPERATION &&
                            (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
                        {
                                OperationDepsNode *from = (OperationDepsNode *)rel->from;
 -                              IDDepsNode *id_from_node = from->owner->owner;
 -                              if ((id_from_node->layers & layers) != 0 &&
 -                                  (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
 -                              {
 +                              if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                                        ++node->num_links_pending;
                                }
                        }
        }
  }
  
 -static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
 +static void calculate_pending_parents(Depsgraph *graph)
  {
        const int num_operations = graph->operations.size();
-       const bool do_threads = (num_operations > 256);
        CalculatePengindData data;
        data.graph = graph;
 -      data.layers = layers;
        ParallelRangeSettings settings;
        BLI_parallel_range_settings_defaults(&settings);
-       settings.use_threading = do_threads;
+       settings.min_iter_per_thread = 1024;
        BLI_task_parallel_range(0,
                                num_operations,
                                &data,
  static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
  {
        const bool do_stats = state->do_stats;
 -      calculate_pending_parents(graph, state->layers);
 +      calculate_pending_parents(graph);
        /* Clear tags and other things which needs to be clear. */
        foreach (OperationDepsNode *node, graph->operations) {
                node->done = 0;
   *   dec_parents: Decrement pending parents count, true when child nodes are
   *                scheduled after a task has been completed.
   */
 -static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
 +static void schedule_node(TaskPool *pool, Depsgraph *graph,
                            OperationDepsNode *node, bool dec_parents,
                            const int thread_id)
  {
 -      unsigned int id_layers = node->owner->owner->layers;
 -
 -      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
 -          (id_layers & layers) != 0)
 -      {
 +      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                if (dec_parents) {
                        BLI_assert(node->num_links_pending > 0);
                        atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
                        if (!is_scheduled) {
                                if (node->is_noop()) {
                                        /* skip NOOP node, schedule children right away */
 -                                      schedule_children(pool, graph, node, layers, thread_id);
 +                                      schedule_children(pool, graph, node, thread_id);
                                }
                                else {
                                        /* children are scheduled once this task is completed */
        }
  }
  
 -static void schedule_graph(TaskPool *pool,
 -                           Depsgraph *graph,
 -                           const unsigned int layers)
 +static void schedule_graph(TaskPool *pool, Depsgraph *graph)
  {
        foreach (OperationDepsNode *node, graph->operations) {
 -              schedule_node(pool, graph, layers, node, false, 0);
 +              schedule_node(pool, graph, node, false, 0);
        }
  }
  
  static void schedule_children(TaskPool *pool,
                                Depsgraph *graph,
                                OperationDepsNode *node,
 -                              const unsigned int layers,
                                const int thread_id)
  {
        foreach (DepsRelation *rel, node->outlinks) {
                }
                schedule_node(pool,
                              graph,
 -                            layers,
                              child,
                              (rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
                              thread_id);
   * \note Time sources should be all valid!
   */
  void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
 -                             Depsgraph *graph,
 -                             const unsigned int layers)
 +                             Depsgraph *graph)
  {
        /* Nothing to update, early out. */
        if (BLI_gset_size(graph->entry_tags) == 0) {
                return;
        }
 -      DEG_DEBUG_PRINTF("%s: layers:%u, graph->layers:%u\n",
 -                       __func__,
 -                       layers,
 -                       graph->layers);
        /* Set time for the current graph evaluation context. */
        TimeSourceDepsNode *time_src = graph->find_time_source();
 +      eval_ctx->depsgraph = (::Depsgraph *)graph;
 +      eval_ctx->view_layer = DEG_get_evaluated_view_layer((::Depsgraph *)graph);
        eval_ctx->ctime = time_src->cfra;
        /* Set up evaluation context for depsgraph itself. */
        DepsgraphEvalState state;
        state.eval_ctx = eval_ctx;
        state.graph = graph;
 -      state.layers = layers;
        state.do_stats = (G.debug_value != 0);
        /* Set up task scheduler and pull for threaded evaluation. */
        TaskScheduler *task_scheduler;
        /* Prepare all nodes for evaluation. */
        initialize_execution(&state, graph);
        /* Do actual evaluation now. */
 -      schedule_graph(task_pool, graph, layers);
 +      schedule_graph(task_pool, graph);
        BLI_task_pool_work_and_wait(task_pool);
        BLI_task_pool_free(task_pool);
        /* Finalize statistics gathering. This is because we only gather single
index c3b1f56a71b02bdde5d7d6e83fc7434b848ed4a4,daf008ddb7dc63344e25a1365022edc45f23a0b0..74c3cd28455fac68b486dc4ad99df7412c925877
@@@ -51,7 -51,6 +51,7 @@@ extern "C" 
  #include "intern/nodes/deg_node_operation.h"
  
  #include "intern/depsgraph_intern.h"
 +#include "intern/eval/deg_eval_copy_on_write.h"
  #include "util/deg_util_foreach.h"
  
  namespace DEG {
@@@ -71,6 -70,19 +71,6 @@@ typedef std::deque<OperationDepsNode *
  
  namespace {
  
 -// TODO(sergey): De-duplicate with depsgraph_tag,cc
 -void lib_id_recalc_tag(Main *bmain, ID *id)
 -{
 -      id->recalc |= ID_RECALC;
 -      DEG_id_type_tag(bmain, GS(id->name));
 -}
 -
 -void lib_id_recalc_data_tag(Main *bmain, ID *id)
 -{
 -      id->recalc |= ID_RECALC_DATA;
 -      DEG_id_type_tag(bmain, GS(id->name));
 -}
 -
  void flush_init_operation_node_func(
          void *__restrict data_v,
          const int i,
@@@ -100,7 -112,7 +100,7 @@@ BLI_INLINE void flush_prepare(Depsgrap
                const int num_operations = graph->operations.size();
                ParallelRangeSettings settings;
                BLI_parallel_range_settings_defaults(&settings);
-               settings.use_threading = (num_operations > 256);
+               settings.min_iter_per_thread = 1024;
                BLI_task_parallel_range(0, num_operations,
                                        graph,
                                        flush_init_operation_node_func,
                const int num_id_nodes = graph->id_nodes.size();
                ParallelRangeSettings settings;
                BLI_parallel_range_settings_defaults(&settings);
-               settings.use_threading = (num_id_nodes > 256);
+               settings.min_iter_per_thread = 1024;
                BLI_task_parallel_range(0, num_id_nodes,
                                        graph,
                                        flush_init_id_node_func,
@@@ -134,10 -146,9 +134,10 @@@ BLI_INLINE void flush_handle_id_node(ID
  }
  
  /* TODO(sergey): We can reduce number of arguments here. */
 -BLI_INLINE void flush_handle_component_node(Depsgraph * /*graph*/,
 +BLI_INLINE void flush_handle_component_node(Depsgraph *graph,
                                              IDDepsNode *id_node,
                                              ComponentDepsNode *comp_node,
 +                                            bool use_copy_on_write,
                                              FlushQueue *queue)
  {
        /* We only handle component once. */
                return;
        }
        comp_node->done = COMPONENT_STATE_DONE;
 +      /* Currently this is needed to get object->mesh to be replaced with
 +       * original mesh (rather than being evaluated_mesh).
 +       *
 +       * TODO(sergey): This is something we need to avoid.
 +       */
 +      if (use_copy_on_write && comp_node->depends_on_cow()) {
 +              ComponentDepsNode *cow_comp =
 +                      id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
 +              cow_comp->tag_update(graph);
 +      }
        /* Tag all required operations in component for update.  */
        foreach (OperationDepsNode *op, comp_node->operations) {
 -              op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
 -      }
 -      if (GS(id_node->id->name) == ID_OB) {
 -              Object *object = (Object *)id_node->id;
 -              /* This code is used to preserve those areas which does
 -               * direct object update,
 +              /* We don't want to flush tags in "upstream" direction for
 +               * certain types of operations.
                 *
 -               * Plus it ensures visibility changes and relations and
 -               * layers visibility update has proper flags to work with.
 +               * TODO(sergey): Need a more generic solution for this.
                 */
 -              switch (comp_node->type) {
 -                      case DEG_NODE_TYPE_UNDEFINED:
 -                      case DEG_NODE_TYPE_OPERATION:
 -                      case DEG_NODE_TYPE_TIMESOURCE:
 -                      case DEG_NODE_TYPE_ID_REF:
 -                      case DEG_NODE_TYPE_SEQUENCER:
 -                      case NUM_DEG_NODE_TYPES:
 -                              /* Ignore, does not translate to object component. */
 -                              BLI_assert(!"This should never happen!");
 -                              break;
 -                      case DEG_NODE_TYPE_ANIMATION:
 -                              object->recalc |= OB_RECALC_TIME;
 -                              break;
 -                      case DEG_NODE_TYPE_TRANSFORM:
 -                              object->recalc |= OB_RECALC_OB;
 -                              break;
 -                      case DEG_NODE_TYPE_GEOMETRY:
 -                      case DEG_NODE_TYPE_EVAL_POSE:
 -                      case DEG_NODE_TYPE_BONE:
 -                      case DEG_NODE_TYPE_EVAL_PARTICLES:
 -                      case DEG_NODE_TYPE_SHADING:
 -                      case DEG_NODE_TYPE_CACHE:
 -                      case DEG_NODE_TYPE_PROXY:
 -                              object->recalc |= OB_RECALC_DATA;
 -                              break;
 -                      case DEG_NODE_TYPE_PARAMETERS:
 -                              break;
 +              if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
 +                      continue;
                }
 +              op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
        }
        /* When some target changes bone, we might need to re-run the
         * whole IK solver, otherwise result might be unpredictable.
@@@ -207,41 -237,19 +207,41 @@@ BLI_INLINE OperationDepsNode *flush_sch
        return result;
  }
  
 +/* NOTE: It will also accumulate flags from changed components. */
  BLI_INLINE void flush_editors_id_update(Main *bmain,
 -                                        Depsgraph *graph)
 +                                        Depsgraph *graph,
 +                                        const DEGEditorUpdateContext *update_ctx)
  {
        foreach (IDDepsNode *id_node, graph->id_nodes) {
                if (id_node->done != ID_STATE_MODIFIED) {
                        continue;
                }
 +              DEG_id_type_tag(bmain, GS(id_node->id_orig->name));
                /* TODO(sergey): Do we need to pass original or evaluated ID here? */
 -              ID *id = id_node->id;
 -              deg_editors_id_update(bmain, id);
 -              lib_id_recalc_tag(bmain, id);
 -              /* TODO(sergey): For until we've got proper data nodes in the graph. */
 -              lib_id_recalc_data_tag(bmain, id);
 +              ID *id_orig = id_node->id_orig;
 +              ID *id_cow = id_node->id_cow;
 +              /* Copy tag from original data to CoW storage.
 +               * This is because DEG_id_tag_update() sets tags on original
 +               * data.
 +               */
 +              id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL);
 +              /* Gather recalc flags from all changed components. */
 +              GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
 +              {
 +                      if (comp_node->done != COMPONENT_STATE_DONE) {
 +                              continue;
 +                      }
 +                      DepsNodeFactory *factory = deg_type_get_factory(comp_node->type);
 +                      BLI_assert(factory != NULL);
 +                      id_cow->recalc |= factory->id_recalc_tag();
 +              }
 +              GHASH_FOREACH_END();
 +              DEG_DEBUG_PRINTF("Accumulated recalc bits for %s: %u\n",
 +                               id_orig->name, (unsigned int)id_cow->recalc);
 +              /* Inform editors. */
 +              if (deg_copy_on_write_is_expanded(id_cow)) {
 +                      deg_editors_id_update(update_ctx, id_cow);
 +              }
        }
  }
  
   */
  void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
  {
 +      const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write();
        /* Sanity checks. */
        BLI_assert(bmain != NULL);
        BLI_assert(graph != NULL);
        /* Starting from the tagged "entry" nodes, flush outwards. */
        FlushQueue queue;
        flush_schedule_entrypoints(graph, &queue);
 +      /* Prepare update context for editors. */
 +      DEGEditorUpdateContext update_ctx;
 +      update_ctx.bmain = bmain;
 +      update_ctx.scene = graph->scene;
 +      update_ctx.view_layer = graph->view_layer;
        /* Do actual flush. */
        while (!queue.empty()) {
                OperationDepsNode *op_node = queue.front();
                        flush_handle_component_node(graph,
                                                    id_node,
                                                    comp_node,
 +                                                  use_copy_on_write,
                                                    &queue);
                        /* Flush to nodes along links. */
                        op_node = flush_schedule_children(op_node, &queue);
                }
        }
        /* Inform editors about all changes. */
 -      flush_editors_id_update(bmain, graph);
 +      flush_editors_id_update(bmain, graph, &update_ctx);
  }
  
  static void graph_clear_func(
@@@ -310,10 -311,9 +310,9 @@@ void deg_graph_clear_tags(Depsgraph *gr
  {
        /* Go over all operation nodes, clearing tags. */
        const int num_operations = graph->operations.size();
-       const bool do_threads = num_operations > 256;
        ParallelRangeSettings settings;
        BLI_parallel_range_settings_defaults(&settings);
-       settings.use_threading = do_threads;
+       settings.min_iter_per_thread = 1024;
        BLI_task_parallel_range(0, num_operations,
                                graph,
                                graph_clear_func,
index 3976433db932dc93d27914a493e93fdf83c89702,8f197ce3b997b1719e54347e0aaaa043c99e8d03..47b51ac170b6efefc942b60e371c7e7988e8d85f
@@@ -47,6 -47,8 +47,6 @@@
  #include "BKE_deform.h"
  #include "BKE_editmesh.h"
  
 -#include "depsgraph_private.h"
 -
  #include "MEM_guardedalloc.h"
  
  #include "MOD_util.h"
@@@ -120,6 -122,23 +120,6 @@@ static void foreachObjectLink
        walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
  }
  
 -static void updateDepgraph(ModifierData *md, DagForest *forest,
 -                           struct Main *UNUSED(bmain),
 -                           struct Scene *UNUSED(scene),
 -                           Object *UNUSED(ob),
 -                           DagNode *obNode)
 -{
 -      MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
 -
 -      if (mmd->object) {
 -              DagNode *curNode = dag_get_node(forest, mmd->object);
 -
 -              dag_add_relation(forest, curNode, obNode,
 -                               DAG_RL_DATA_DATA | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_OB_OB,
 -                               "Mesh Deform Modifier");
 -      }
 -}
 -
  static void updateDepsgraph(ModifierData *md,
                              struct Main *UNUSED(bmain),
                              struct Scene *UNUSED(scene),
@@@ -275,7 -294,7 +275,7 @@@ static void meshdeform_vert_task
  }
  
  static void meshdeformModifier_do(
 -        ModifierData *md, Object *ob, DerivedMesh *dm,
 +        ModifierData *md, const struct EvaluationContext *eval_ctx, Object *ob, DerivedMesh *dm,
          float (*vertexCos)[3], int numVerts)
  {
        MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
         */
        if (mmd->object == md->scene->obedit) {
                BMEditMesh *em = BKE_editmesh_from_object(mmd->object);
 -              tmpdm = editbmesh_get_derived_cage_and_final(md->scene, mmd->object, em, 0, &cagedm);
 +              tmpdm = editbmesh_get_derived_cage_and_final(eval_ctx, md->scene, mmd->object, em, 0, &cagedm);
                if (tmpdm)
                        tmpdm->release(tmpdm);
        }
        /* Do deformation. */
        ParallelRangeSettings settings;
        BLI_parallel_range_settings_defaults(&settings);
-       settings.use_threading = (totvert > 1000);
+       settings.min_iter_per_thread = 16;
        BLI_task_parallel_range(0, totvert,
                                &data,
                                meshdeform_vert_task,
        cagedm->release(cagedm);
  }
  
 -static void deformVerts(ModifierData *md, Object *ob,
 +static void deformVerts(ModifierData *md, const struct EvaluationContext *eval_ctx, Object *ob,
                          DerivedMesh *derivedData,
                          float (*vertexCos)[3],
                          int numVerts,
  
        modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
  
 -      meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
 +      meshdeformModifier_do(md, eval_ctx, ob, dm, vertexCos, numVerts);
  
        if (dm && dm != derivedData)
                dm->release(dm);
  }
  
 -static void deformVertsEM(ModifierData *md, Object *ob,
 +static void deformVertsEM(ModifierData *md, const struct EvaluationContext *eval_ctx, Object *ob,
                            struct BMEditMesh *UNUSED(editData),
                            DerivedMesh *derivedData,
                            float (*vertexCos)[3],
  {
        DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
  
 -      meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
 +      meshdeformModifier_do(md, eval_ctx, ob, dm, vertexCos, numVerts);
  
        if (dm && dm != derivedData)
                dm->release(dm);
@@@ -524,6 -543,7 +524,6 @@@ ModifierTypeInfo modifierType_MeshDefor
        /* requiredDataMask */  requiredDataMask,
        /* freeData */          freeData,
        /* isDisabled */        isDisabled,
 -      /* updateDepgraph */    updateDepgraph,
        /* updateDepsgraph */   updateDepsgraph,
        /* dependsOnTime */     NULL,
        /* dependsOnNormals */  NULL,