Subdiv: Initial implementation of CCG
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 6 Sep 2018 15:06:17 +0000 (17:06 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 11 Sep 2018 14:37:02 +0000 (16:37 +0200)
Attempts to substitude CCGDM with an OpenSubdiv based structure
which has less abstraction levels. The missing part in this
substitude is a face pointers which old CCGDM/multires code was
using to stitch faces (averaging boundaries).

Another curial bit missing: "reshaping" of multires CD_MDISPS
to the state of new PBVH grids.

The new code is only available when OpenSubdiv modifier is
enabled (WITH_OPENSUBDIV_MODIFIER=ON) and with debug value of
128. This is so this WIP code is not interfering with current
production machines in the studio.

Reviewers: brecht

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D3685

source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/BKE_subdiv.h
source/blender/blenkernel/BKE_subdiv_ccg.h
source/blender/blenkernel/intern/mesh_runtime.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/subdiv_ccg.c
source/blender/blenkernel/intern/subdiv_stats.c
source/blender/editors/sculpt_paint/paint_hide.c
source/blender/makesdna/DNA_mesh_types.h
source/blender/modifiers/intern/MOD_multires.c
source/blender/modifiers/intern/MOD_subsurf.c

index c440a634c9ff364669fef1f8e0f17845f254bb1a..ade23a2a9ca01f3f4ee5dea68c710bf86a4240f3 100644 (file)
@@ -261,7 +261,7 @@ int BKE_sculpt_mask_layers_ensure(struct Object *ob,
                                   struct MultiresModifierData *mmd);
 void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
 
-struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Object *ob, struct Mesh *me_eval_deform);
+struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob);
 
 enum {
        SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
index 4ebb5d1ac666bdab2d7b1df6f87fbdac80928a46..09fcce369d49d8201a5daf7221102c848852bb98 100644 (file)
@@ -66,6 +66,8 @@ typedef enum eSubdivStatsValue {
        SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY,
        SUBDIV_STATS_EVALUATOR_CREATE,
        SUBDIV_STATS_EVALUATOR_REFINE,
+       SUBDIV_STATS_SUBDIV_TO_CCG,
+       SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS,
 
        NUM_SUBDIV_STATS_VALUES,
 } eSubdivStatsValue;
@@ -86,6 +88,10 @@ typedef struct SubdivStats {
                        double evaluator_creation_time;
                        /* Time spent on evaluator->refine(). */
                        double evaluator_refine_time;
+                       /* Total time spent on whole CCG creation. */
+                       double subdiv_to_ccg_time;
+                       /* Time spent on CCG elements evaluation/initialization. */
+                       double subdiv_to_ccg_elements_time;
                };
                double values_[NUM_SUBDIV_STATS_VALUES];
        };
index b1acf43ad25436454485549e54d6d5dc81ae30d1..8f8a605d30993040261d8fe23146c80c3d856a75 100644 (file)
 #define __BKE_SUBDIV_CCG_H__
 
 #include "BKE_customdata.h"
+#include "BLI_bitmap.h"
 #include "BLI_sys_types.h"
 
 struct CCGElem;
 struct CCGKey;
+struct DMFlagMat;
 struct Mesh;
 struct Subdiv;
 
@@ -67,7 +69,12 @@ typedef struct SubdivCCG {
         * corresponding to face-corners of coarse mesh, each grid has
         * grid_size^2 elements.
         */
+       /* Indexed by a grid index, points to a grid data which is stored in
+        * grids_storage.
+        */
        struct CCGElem **grids;
+       /* Flat array of all grids' data. */
+       unsigned char *grids_storage;
        int num_grids;
        /* Loose edges, each array element contains grid_size elements
         * corresponding to vertices created by subdividing coarse edges.
@@ -91,6 +98,9 @@ typedef struct SubdivCCG {
        int normal_offset;
        int mask_offset;
 
+       struct DMFlagMat *grid_flag_mats;
+       BLI_bitmap **grid_hidden;
+
        /* TODO(sergey): Consider adding some accessors to a "decoded" geometry,
         * to make integration with draw manager and such easy.
         */
@@ -106,9 +116,18 @@ struct SubdivCCG *BKE_subdiv_to_ccg(
         const SubdivToCCGSettings *settings,
         const struct Mesh *coarse_mesh);
 
+
 /* Destroy CCG representation of subdivision surface. */
 void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg);
 
+/* Helper function, creates Mesh structure which is properly setup to use
+ * grids.
+ */
+struct Mesh *BKE_subdiv_to_ccg_mesh(
+        struct Subdiv *subdiv,
+        const SubdivToCCGSettings *settings,
+        const struct Mesh *coarse_mesh);
+
 /* Create a key for accessing grid elements at a given level. */
 void BKE_subdiv_ccg_key(
         struct CCGKey *key, const SubdivCCG *subdiv_ccg, int level);
index 60699589a7734a9d60f86730ead905ae4bbc7f2f..51dd9a9ea3a03b1bc3c2b650a9e9ba5eda819014 100644 (file)
@@ -43,6 +43,7 @@
 #include "BKE_bvhutils.h"
 #include "BKE_mesh.h"
 #include "BKE_mesh_runtime.h"
+#include "BKE_subdiv_ccg.h"
 
 /* -------------------------------------------------------------------- */
 /** \name Mesh Runtime Struct Utils
@@ -196,6 +197,11 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
 {
        bvhcache_free(&mesh->runtime.bvh_cache);
        MEM_SAFE_FREE(mesh->runtime.looptris.array);
+       /* TODO(sergey): Does this really belong here? */
+       if (mesh->runtime.subsurf_ccg != NULL) {
+               BKE_subdiv_ccg_destroy(mesh->runtime.subsurf_ccg);
+               mesh->runtime.subsurf_ccg = NULL;
+       }
 }
 
 /** \} */
index 12cdb4586c122396404ad882281c4533bc1f449e..edea8784715e7bcdbdea97dcdf2c4e890cafb8a8 100644 (file)
@@ -55,6 +55,7 @@
 
 #include "BKE_animsys.h"
 #include "BKE_brush.h"
+#include "BKE_ccg.h"
 #include "BKE_colortools.h"
 #include "BKE_deform.h"
 #include "BKE_main.h"
@@ -72,6 +73,7 @@
 #include "BKE_object.h"
 #include "BKE_paint.h"
 #include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
 #include "BKE_subsurf.h"
 
 #include "DEG_depsgraph.h"
@@ -910,7 +912,6 @@ void BKE_sculpt_update_mesh_elements(
        ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
 
        Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
-       Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
 
        /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
        if (mmd && ob->mode & OB_MODE_SCULPT) {
@@ -931,7 +932,7 @@ void BKE_sculpt_update_mesh_elements(
                ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
        }
 
-       PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform);
+       PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
        BLI_assert(pbvh == ss->pbvh);
        UNUSED_VARS_NDEBUG(pbvh);
        MEM_SAFE_FREE(ss->pmap);
@@ -1139,7 +1140,7 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
        return pbvh;
 }
 
-static PBVH *build_regular_mesh_pbvh(Object *ob, Mesh *me_eval_deform)
+static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
 {
        Mesh *me = BKE_object_get_original_mesh(ob);
        const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
@@ -1174,7 +1175,24 @@ static PBVH *build_regular_mesh_pbvh(Object *ob, Mesh *me_eval_deform)
        return pbvh;
 }
 
-PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform)
+static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
+{
+       CCGKey key;
+       BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+       PBVH *pbvh = BKE_pbvh_new();
+       BKE_pbvh_build_grids(
+               pbvh,
+               subdiv_ccg->grids, subdiv_ccg->num_grids,
+               &key,
+               NULL,
+               subdiv_ccg->grid_flag_mats,
+               subdiv_ccg->grid_hidden);
+       pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+       pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+       return pbvh;
+}
+
+PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
 {
        if (ob == NULL || ob->sculpt == NULL) {
                return NULL;
@@ -1189,8 +1207,17 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform)
                /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
                pbvh = build_pbvh_for_dynamic_topology(ob);
        }
-       else if (ob->type == OB_MESH) {
-               pbvh = build_regular_mesh_pbvh(ob, me_eval_deform);
+       else {
+               Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+               Mesh *mesh_eval = object_eval->data;
+               if (mesh_eval->runtime.subsurf_ccg != NULL) {
+                       pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subsurf_ccg);
+               }
+               else if (ob->type == OB_MESH) {
+                       Mesh *me_eval_deform = mesh_get_eval_deform(
+                               depsgraph, DEG_get_evaluated_scene(depsgraph), ob, CD_MASK_BAREMESH);
+                       pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+               }
        }
 
        ob->sculpt->pbvh = pbvh;
index d1769c5324dcf9b35687bf7ea54a3f74ddd014e5..33785c09936179fc5e9168dd4b5b57d71589b452 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
+#include "BLI_math_bits.h"
+#include "BLI_task.h"
+
+#include "BKE_DerivedMesh.h"
 #include "BKE_ccg.h"
+#include "BKE_mesh.h"
 #include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+
+/* =============================================================================
+ * Generally useful internal helpers.
+ */
+
+/* For a given subdivision level (NOT the refinement level) get resolution
+ * of grid.
+ */
+static int grid_size_for_level_get(const SubdivCCG *subdiv_ccg, int level)
+{
+       BLI_assert(level >= 1);
+       BLI_assert(level <= subdiv_ccg->level);
+       UNUSED_VARS_NDEBUG(subdiv_ccg);
+       return (1 << (level - 1)) + 1;
+}
+
+/* Number of floats in per-vertex elements.  */
+static int num_element_float_get(const SubdivCCG *subdiv_ccg)
+{
+       /* We always have 3 floats for coordinate. */
+       int num_floats = 3;
+       if (subdiv_ccg->has_normal) {
+               num_floats += 3;
+       }
+       if (subdiv_ccg->has_mask) {
+               num_floats += 1;
+       }
+       return num_floats;
+}
+
+/* Per-vertex element size in bytes. */
+static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
+{
+       return sizeof(float) * num_element_float_get(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Internal helpers for CCG creation.
+ */
 
 static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg,
                                    const SubdivToCCGSettings *settings)
 {
        /* CCG always contains coordinates. Rest of layers are coming after them. */
        int layer_offset = sizeof(float) * 3;
-       /* Normals. */
+       /* Mask. */
+       if (settings->need_mask) {
+               subdiv_ccg->has_mask = true;
+               subdiv_ccg->mask_offset = layer_offset;
+               layer_offset += sizeof(float);
+       }
+       else {
+               subdiv_ccg->has_mask = false;
+               subdiv_ccg->mask_offset = -1;
+       }
+       /* Normals.
+        *
+        * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter
+        * here, but some other area might in theory depend memory layout.
+        */
        if (settings->need_normal) {
                subdiv_ccg->has_normal = true;
                subdiv_ccg->normal_offset = layer_offset;
@@ -52,65 +111,264 @@ static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg,
                subdiv_ccg->has_normal = false;
                subdiv_ccg->normal_offset = -1;
        }
-       /* Mask. */
-       if (settings->need_mask) {
-               subdiv_ccg->has_mask = true;
-               subdiv_ccg->mask_offset = layer_offset;
-               layer_offset += sizeof(float);
+}
+
+/* NOTE: Grid size and layer flags are to be filled in before calling this
+ * function.
+ */
+static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg,
+                                      const Mesh *coarse_mesh)
+{
+       const int element_size = element_size_bytes_get(subdiv_ccg);
+       /* Allocate memory for surface grids. */
+       const int num_grids = coarse_mesh->totloop;
+       const int grid_size = grid_size_for_level_get(
+               subdiv_ccg, subdiv_ccg->level);
+       const int grid_area = grid_size * grid_size;
+       subdiv_ccg->num_grids = num_grids;
+       subdiv_ccg->grids =
+               MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
+       subdiv_ccg->grids_storage = MEM_calloc_arrayN(
+               num_grids, ((size_t)grid_area) * element_size,
+               "subdiv ccg grids storage");
+       const size_t grid_size_in_bytes = (size_t)grid_area * element_size;
+       for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+               const size_t grid_offset = grid_size_in_bytes * grid_index;
+               subdiv_ccg->grids[grid_index] =
+                       (CCGElem *)&subdiv_ccg->grids_storage[grid_offset];
+       }
+       /* Grid material flags. */
+       subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN(
+               num_grids, sizeof(DMFlagMat), "ccg grid material flags");
+       /* Grid hidden flags. */
+       subdiv_ccg->grid_hidden = MEM_calloc_arrayN(
+               num_grids, sizeof(BLI_bitmap *), "ccg grid material flags");
+       for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+               subdiv_ccg->grid_hidden[grid_index] =
+                       BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
+       }
+       /* TOOD(sergey): Allocate memory for loose elements. */
+}
+
+/* =============================================================================
+ * Grids evaluation.
+ */
+
+typedef struct CCGEvalGridsData {
+       SubdivCCG *subdiv_ccg;
+       Subdiv *subdiv;
+       const Mesh *coarse_mesh;
+       int *face_petx_offset;
+} CCGEvalGridsData;
+
+static void subdiv_ccg_eval_grid_element(
+        CCGEvalGridsData *data,
+        const int ptex_face_index,
+        const float u, const float v,
+        unsigned char *element)
+{
+       /* TODO(sergey): Support displacement. */
+       if (data->subdiv_ccg->has_normal) {
+               BKE_subdiv_eval_limit_point_and_normal(
+                       data->subdiv, ptex_face_index, u, v,
+                       (float *)element,
+                       (float *)(element + data->subdiv_ccg->normal_offset));
        }
        else {
-               subdiv_ccg->has_mask = false;
-               subdiv_ccg->mask_offset = -1;
+               BKE_subdiv_eval_limit_point(
+                       data->subdiv, ptex_face_index, u, v, (float *)element);
        }
 }
 
-static int grid_size_for_level_get(const SubdivCCG *subdiv_ccg, int level)
+BLI_INLINE void rotate_corner_to_quad(const int corner,
+                                         const float u, const float v,
+                                      float *r_u, float *r_v)
 {
-       BLI_assert(level >= 1);
-       BLI_assert(level <= subdiv_ccg->level);
-       UNUSED_VARS_NDEBUG(subdiv_ccg);
-       return (1 << (level - 1)) + 1;
+       if (corner == 0) {
+               *r_u = 0.5f - v * 0.5f;
+               *r_v = 0.5f - u * 0.5f;
+       }
+       else if (corner == 1) {
+               *r_u = 0.5f + u * 0.5f;
+               *r_v = 0.5f - v * 0.5f;
+       }
+       else if (corner == 2) {
+               *r_u = 0.5f + v * 0.5f;
+               *r_v = 0.5f + u * 0.5f;
+       }
+       else if (corner == 3) {
+               *r_u = 0.5f - u * 0.5f;
+               *r_v = 0.5f + v * 0.5f;
+       }
+       else {
+               BLI_assert(!"Unexpected corner configuration");
+       }
 }
 
-/* Per-vertex element size in bytes. */
-static int element_size_get(const SubdivCCG *subdiv_ccg)
+static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
+                                         const MPoly *coarse_poly)
 {
-       /* We always have 3 floats for coordinate. */
-       int num_floats = 3;
-       if (subdiv_ccg->has_normal) {
-               num_floats += 3;
+       SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+       const int coarse_poly_index = coarse_poly - data->coarse_mesh->mpoly;
+       const int ptex_face_index = data->face_petx_offset[coarse_poly_index];
+       const int grid_size = subdiv_ccg->grid_size;
+       const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+       const int element_size = element_size_bytes_get(subdiv_ccg);
+       for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+               unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
+                       coarse_poly->loopstart + corner];
+               for (int y = 0; y < grid_size; y++) {
+                       const float grid_v = (float)y * grid_size_1_inv;
+                       for (int x = 0; x < grid_size; x++) {
+                               const float grid_u = (float)x * grid_size_1_inv;
+                               float u, v;
+                               rotate_corner_to_quad(corner, grid_u, grid_v, &u, &v);
+                               const size_t grid_element_index = (size_t)y * grid_size + x;
+                               const size_t grid_element_offset =
+                                       grid_element_index * element_size;
+                               subdiv_ccg_eval_grid_element(
+                                       data,
+                                       ptex_face_index, u, v,
+                                       &grid[grid_element_offset]);
+                       }
+               }
        }
-       if (subdiv_ccg->has_mask) {
-               num_floats += 1;
+}
+
+static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
+                                         const MPoly *coarse_poly)
+{
+       SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+       const int coarse_poly_index = coarse_poly - data->coarse_mesh->mpoly;
+       const int grid_size = subdiv_ccg->grid_size;
+       const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+       const int element_size = element_size_bytes_get(subdiv_ccg);
+       for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+               unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
+                       coarse_poly->loopstart + corner];
+               for (int y = 0; y < grid_size; y++) {
+                       const float u = 1.0f - ((float)y * grid_size_1_inv);
+                       for (int x = 0; x < grid_size; x++) {
+                               const float v = 1.0f - ((float)x * grid_size_1_inv);
+                               const int ptex_face_index =
+                                       data->face_petx_offset[coarse_poly_index] + corner;
+                               const size_t grid_element_index = (size_t)y * grid_size + x;
+                               const size_t grid_element_offset =
+                                       grid_element_index * element_size;
+                               subdiv_ccg_eval_grid_element(
+                                       data,
+                                       ptex_face_index, u, v,
+                                       &grid[grid_element_offset]);
+                       }
+               }
+       }
+}
+
+static void subdiv_ccg_eval_grids_task(
+        void *__restrict userdata_v,
+        const int coarse_poly_index,
+        const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+       CCGEvalGridsData *data = userdata_v;
+       const Mesh *coarse_mesh = data->coarse_mesh;
+       const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+       const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+       if (coarse_poly->totloop == 4) {
+               subdiv_ccg_eval_regular_grid(data, coarse_poly);
+       }
+       else {
+               subdiv_ccg_eval_special_grid(data, coarse_poly);
+       }
+}
+
+static bool subdiv_ccg_evaluate_grids(SubdivCCG *subdiv_ccg,
+                                         Subdiv *subdiv,
+                                      const Mesh *coarse_mesh)
+{
+       /* Make sure evaluator is ready. */
+       if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+               if (coarse_mesh->totpoly) {
+                       return false;
+               }
        }
-       return sizeof(float) * num_floats;
+       /* Initialize data passed to all the tasks. */
+       CCGEvalGridsData data;
+       data.subdiv_ccg = subdiv_ccg;
+       data.subdiv = subdiv;
+       data.coarse_mesh = coarse_mesh;
+       data.face_petx_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+       /* Threaded grids evaluation/ */
+       ParallelRangeSettings parallel_range_settings;
+       BLI_parallel_range_settings_defaults(&parallel_range_settings);
+       BLI_task_parallel_range(0, coarse_mesh->totpoly,
+                               &data,
+                               subdiv_ccg_eval_grids_task,
+                               &parallel_range_settings);
+       return true;
 }
 
+/* =============================================================================
+ * Public API.
+ */
+
 SubdivCCG *BKE_subdiv_to_ccg(
-        Subdiv *UNUSED(subdiv),
+        Subdiv *subdiv,
         const SubdivToCCGSettings *settings,
-        const Mesh *UNUSED(coarse_mesh))
+        const Mesh *coarse_mesh)
 {
-       SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG *), "subdiv ccg");
-       subdiv_ccg->level = settings->resolution >> 1;
+       BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+       SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
+       subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
        subdiv_ccg->grid_size =
                grid_size_for_level_get(subdiv_ccg, subdiv_ccg->level);
        subdiv_ccg_init_layers(subdiv_ccg, settings);
-       return NULL;
+       subdiv_ccg_alloc_elements(subdiv_ccg, coarse_mesh);
+       if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, coarse_mesh)) {
+               BKE_subdiv_ccg_destroy(subdiv_ccg);
+               BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+               return NULL;
+       }
+       BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+       return subdiv_ccg;
+}
+
+Mesh *BKE_subdiv_to_ccg_mesh(
+        Subdiv *subdiv,
+        const SubdivToCCGSettings *settings,
+        const Mesh *coarse_mesh)
+{
+       SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg(
+               subdiv, settings, coarse_mesh);
+       if (subdiv_ccg == NULL) {
+               return NULL;
+       }
+       Mesh *result = BKE_mesh_new_nomain_from_template(
+               coarse_mesh, 0, 0, 0, 0, 0);
+       result->runtime.subsurf_ccg = subdiv_ccg;
+       return result;
 }
 
 void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
 {
+       const int num_grids = subdiv_ccg->num_grids;
        MEM_SAFE_FREE(subdiv_ccg->grids);
+       MEM_SAFE_FREE(subdiv_ccg->grids_storage);
        MEM_SAFE_FREE(subdiv_ccg->edges);
        MEM_SAFE_FREE(subdiv_ccg->vertices);
+       MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats);
+       if (subdiv_ccg->grid_hidden != NULL) {
+               for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+                       MEM_freeN(subdiv_ccg->grid_hidden[grid_index]);
+               }
+               MEM_freeN(subdiv_ccg->grid_hidden);
+       }
        MEM_freeN(subdiv_ccg);
 }
 
 void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level)
 {
        key->level = level;
-       key->elem_size = element_size_get(subdiv_ccg);
+       key->elem_size = element_size_bytes_get(subdiv_ccg);
        key->grid_size = grid_size_for_level_get(subdiv_ccg, level);
        key->grid_area = key->grid_size * key->grid_size;
        key->grid_bytes = key->elem_size * key->grid_area;
index f2219961ab7d0f84ba3d7ef92aeece052c615450..a0cd1d909b728a3a6c3b708a41b8c347d497b7cd 100644 (file)
@@ -40,6 +40,8 @@ void BKE_subdiv_stats_init(SubdivStats *stats)
        stats->subdiv_to_mesh_geometry_time = 0.0;
        stats->evaluator_creation_time = 0.0;
        stats->evaluator_refine_time = 0.0;
+       stats->subdiv_to_ccg_time = 0.0;
+       stats->subdiv_to_ccg_elements_time = 0.0;
 }
 
 void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
@@ -79,6 +81,12 @@ void BKE_subdiv_stats_print(const SubdivStats *stats)
        STATS_PRINT_TIME(stats,
                         evaluator_refine_time,
                         "Evaluator refine time");
+       STATS_PRINT_TIME(stats,
+                        subdiv_to_ccg_time,
+                        "Subdivision to CCG time");
+       STATS_PRINT_TIME(stats,
+                        subdiv_to_ccg_elements_time,
+                        "    Elements time");
 
 #undef STATS_PRINT_TIME
 }
index a0589623f92d55f3cfd23f66e84e01de75ae2d48..0336928a7c9da6a246ae2e551bb6e615a88f2035 100644 (file)
@@ -391,8 +391,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
 
        clip_planes_from_rect(C, clip_planes, &rect);
 
-       Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH);
-       pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform);
+       pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
        BLI_assert(ob->sculpt->pbvh == pbvh);
 
        get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
index a91f2f05c1a4049f5be724c0415c6c3a0a165559..be190d656b4edcee3691826a9617c7c8f052d3bd 100644 (file)
@@ -53,6 +53,7 @@ struct MVert;
 struct Material;
 struct Mesh;
 struct Multires;
+struct SubdivCCG;
 
 #
 #
@@ -83,6 +84,8 @@ struct MLoopTri_Store {
 typedef struct Mesh_Runtime {
        struct EditMeshData *edit_data;
        void *batch_cache;
+       struct SubdivCCG *subsurf_ccg;
+       void  *pad1;
 
        int64_t cd_dirty_vert;
        int64_t cd_dirty_edge;
index 870d91282b6a2da92a36eeeed3a9b47b7b97f142..847b34b7aa6b864573c0e1c99b61e895be170937 100644 (file)
 #include "BLI_utildefines.h"
 
 #include "BKE_cdderivedmesh.h"
+#include "BKE_global.h"
 #include "BKE_mesh.h"
 #include "BKE_multires.h"
 #include "BKE_modifier.h"
 #include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
 #include "BKE_subdiv_mesh.h"
 #include "BKE_subsurf.h"
 
@@ -143,25 +145,74 @@ static DerivedMesh *applyModifier(
 }
 
 #ifdef WITH_OPENSUBDIV_MODIFIER
-static Mesh *applyModifier_subdiv(ModifierData *md,
-                                  const ModifierEvalContext *ctx,
-                                  Mesh *mesh)
+
+/* Subdivide into fully qualified mesh. */
+
+static Mesh *multires_as_mesh(MultiresModifierData *mmd,
+                              const ModifierEvalContext *ctx,
+                              Mesh *mesh,
+                              Subdiv *subdiv)
+{
+       Mesh *result = mesh;
+       const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
+       const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY);
+       const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+       Object *object = ctx->object;
+       SubdivToMeshSettings mesh_settings;
+       BKE_multires_subdiv_mesh_settings_init(
+        &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify);
+       if (mesh_settings.resolution < 3) {
+               return result;
+       }
+       BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+       result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+       return result;
+}
+
+/* Subdivide into CCG. */
+
+static void multires_ccg_settings_init(SubdivToCCGSettings *settings,
+                                       const MultiresModifierData *mmd,
+                                       const ModifierEvalContext *ctx,
+                                       Mesh *mesh)
 {
+       const bool has_mask =
+               CustomData_has_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
        const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
        const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY);
        const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
        Object *object = ctx->object;
+       const int level = multires_get_level(
+               scene, object, mmd, use_render_params, ignore_simplify);
+       settings->resolution = (1 << level) + 1;
+       settings->need_normal = true;
+       settings->need_mask = has_mask;
+}
+
+static Mesh *multires_as_ccg(MultiresModifierData *mmd,
+                             const ModifierEvalContext *ctx,
+                             Mesh *mesh,
+                             Subdiv *subdiv)
+{
+       Mesh *result = mesh;
+       SubdivToCCGSettings ccg_settings;
+       multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh);
+       if (ccg_settings.resolution < 3) {
+               return result;
+       }
+       result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh);
+       return result;
+}
+
+static Mesh *applyModifier_subdiv(ModifierData *md,
+                                  const ModifierEvalContext *ctx,
+                                  Mesh *mesh)
+{
        Mesh *result = mesh;
        MultiresModifierData *mmd = (MultiresModifierData *)md;
        SubdivSettings subdiv_settings;
        BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
-       SubdivToMeshSettings mesh_settings;
-       BKE_multires_subdiv_mesh_settings_init(
-        &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify);
-       if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) {
-               /* NOTE: Shouldn't really happen, is supposed to be catched by
-                * isDisabled() callback.
-                */
+       if (subdiv_settings.level == 0) {
                return result;
        }
        /* TODO(sergey): Try to re-use subdiv when possible. */
@@ -170,8 +221,17 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
                /* Happens on bad topology, ut also on empty input mesh. */
                return result;
        }
-       BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
-       result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+       /* TODO(sergey): Some of production machines are using OpenSubdiv already.
+        * so better not enable semi-finished multires sculpting for now. Will give
+        * a wrong impression that things do work, eben though crucial areas are
+        * styill missing in implementation.
+        */
+       if ((ctx->object->mode & OB_MODE_SCULPT) && G.debug_value == 128) {
+               result = multires_as_ccg(mmd, ctx, mesh, subdiv);
+       }
+       else {
+               result = multires_as_mesh(mmd, ctx, mesh, subdiv);
+       }
        /* TODO(sergey): Cache subdiv somehow. */
        // BKE_subdiv_stats_print(&subdiv->stats);
        BKE_subdiv_free(subdiv);
index ae9ffd076f76ce825d008b03206d379d900c1050..deccec05190c25836280bad118a877fd0664eb2c 100644 (file)
@@ -44,6 +44,7 @@
 #include "BKE_cdderivedmesh.h"
 #include "BKE_scene.h"
 #include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
 #include "BKE_subdiv_mesh.h"
 #include "BKE_subsurf.h"
 
@@ -170,6 +171,8 @@ static void subdiv_settings_init(SubdivSettings *settings,
                BKE_subdiv_fvar_interpolation_from_uv_smooth(smd->uv_smooth);
 }
 
+/* Subdivide into fully qualified mesh. */
+
 static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
                                       const SubsurfModifierData *smd,
                                       const ModifierEvalContext *ctx)
@@ -178,6 +181,50 @@ static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
        settings->resolution = (1 << level) + 1;
 }
 
+static Mesh *subdiv_as_mesh(SubsurfModifierData *smd,
+                            const ModifierEvalContext *ctx,
+                            Mesh *mesh,
+                            Subdiv *subdiv)
+{
+       Mesh *result = mesh;
+       SubdivToMeshSettings mesh_settings;
+       subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+       if (mesh_settings.resolution < 3) {
+               return result;
+       }
+       result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+       return result;
+}
+
+/* Subdivide into CCG. */
+
+static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings,
+                                     const SubsurfModifierData *smd,
+                                     const ModifierEvalContext *ctx)
+{
+       const int level = subdiv_levels_for_modifier_get(smd, ctx);
+       settings->resolution = (1 << level) + 1;
+       settings->need_normal = true;
+       settings->need_mask = false;
+}
+
+static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
+                            const ModifierEvalContext *ctx,
+                            Mesh *mesh,
+                            Subdiv *subdiv)
+{
+       Mesh *result = mesh;
+       SubdivToCCGSettings ccg_settings;
+       subdiv_ccg_settings_init(&ccg_settings, smd, ctx);
+       if (ccg_settings.resolution < 3) {
+               return result;
+       }
+       result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh);
+       return result;
+}
+
+/* Modifier itself. */
+
 static Mesh *applyModifier_subdiv(ModifierData *md,
                                   const ModifierEvalContext *ctx,
                                   Mesh *mesh)
@@ -186,12 +233,7 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
        SubsurfModifierData *smd = (SubsurfModifierData *) md;
        SubdivSettings subdiv_settings;
        subdiv_settings_init(&subdiv_settings, smd);
-       SubdivToMeshSettings mesh_settings;
-       subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
-       if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) {
-               /* NOTE: Shouldn't really happen, is supposed to be catched by
-                * isDisabled() callback.
-                */
+       if (subdiv_settings.level == 0) {
                return result;
        }
        /* TODO(sergey): Try to re-use subdiv when possible. */
@@ -200,7 +242,15 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
                /* Happens on bad topology, ut also on empty input mesh. */
                return result;
        }
-       result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+       /* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
+        * maybe when it is a last modifier in the stack?
+        */
+       if (true) {
+               result = subdiv_as_mesh(smd, ctx, mesh, subdiv);
+       }
+       else {
+               result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
+       }
        /* TODO(sergey): Cache subdiv somehow. */
        // BKE_subdiv_stats_print(&subdiv->stats);
        BKE_subdiv_free(subdiv);