Fix T60575: Multiresolution Crashes when appliing more subdivisions
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 22 Jan 2019 10:48:28 +0000 (11:48 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 22 Jan 2019 10:57:23 +0000 (11:57 +0100)
The issue was caused by intermediate DerivedMesh being created with
scene's Simplify settings taken into account. This is what happens
when one area makes implicit decisions based on whether passed Scene
pointer is not NULL.

Made it so ignoring simplification serttings is an explicit flag,
which makes it easier to follow what's going on.

source/blender/blenkernel/BKE_subsurf.h
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/subsurf_ccg.c

index ba367854c6bac88641e3206e9e02a98094011649..c709eb8075373c96dc8b5eb66523ea9de475723f 100644 (file)
@@ -62,6 +62,7 @@ typedef enum {
        SUBSURF_IN_EDIT_MODE = 8,
        SUBSURF_ALLOC_PAINT_MASK = 16,
        SUBSURF_USE_GPU_BACKEND = 32,
+       SUBSURF_IGNORE_SIMPLIFY = 64,
 } SubsurfFlags;
 
 struct DerivedMesh *subsurf_make_derived_from_derived(
index 2e04394fbc8d576d7583c39df583fb0f18943da4..f0c0046db1f3d7f5aa2e904b5c2dc4c712554714 100644 (file)
@@ -679,10 +679,12 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object
        multires_set_tot_level(ob, mmd, lvl);
 }
 
-static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
+static DerivedMesh *multires_dm_create_local(
+        Scene *scene, Object *ob, DerivedMesh *dm,
+        int lvl, int totlvl, int simple, bool alloc_paint_mask,
+        int flags)
 {
        MultiresModifierData mmd = {{NULL}};
-       MultiresFlags flags = MULTIRES_USE_LOCAL_MMD;
 
        mmd.lvl = lvl;
        mmd.sculptlvl = lvl;
@@ -690,6 +692,7 @@ static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMe
        mmd.totlvl = totlvl;
        mmd.simple = simple;
 
+       flags |= MULTIRES_USE_LOCAL_MMD;
        if (alloc_paint_mask)
                flags |= MULTIRES_ALLOC_PAINT_MASK;
 
@@ -700,10 +703,10 @@ static DerivedMesh *subsurf_dm_create_local(
         Scene *scene, Object *ob, DerivedMesh *dm,
         int lvl,
         bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask,
-        bool for_render)
+        bool for_render,
+        SubsurfFlags flags)
 {
        SubsurfModifierData smd = {{NULL}};
-       SubsurfFlags flags = 0;
 
        smd.levels = smd.renderLevels = lvl;
        smd.quality = 3;
@@ -766,7 +769,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
        /* generate highest level with displacements */
        cddm = CDDM_from_mesh(me);
        DM_set_only_copy(cddm, CD_MASK_BAREMESH);
-       dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0);
+       dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY);
        cddm->release(cddm);
 
        /* copy the new locations of the base verts into the mesh */
@@ -862,7 +865,9 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
        /* subdivide the mesh to highest level without displacements */
        cddm = CDDM_from_mesh(me);
        DM_set_only_copy(cddm, CD_MASK_BAREMESH);
-       origdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, 0, false);
+       origdm = subsurf_dm_create_local(
+               scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+               0, false, SUBSURF_IGNORE_SIMPLIFY);
        cddm->release(cddm);
 
        /* calc disps */
@@ -903,11 +908,13 @@ static void multires_subdivide(
                /* create subsurf DM from original mesh at high level */
                cddm = CDDM_from_mesh(me);
                DM_set_only_copy(cddm, CD_MASK_BAREMESH);
-               highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
+               highdm = subsurf_dm_create_local(
+                       NULL, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+                       has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
                ss = ((CCGDerivedMesh *)highdm)->ss;
 
                /* create multires DM from original mesh at low level */
-               lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask);
+               lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
                BLI_assert(lowdm != cddm);
                cddm->release(cddm);
 
@@ -1224,11 +1231,13 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
                        else cddm = CDDM_from_mesh(me);
                        DM_set_only_copy(cddm, CD_MASK_BAREMESH);
 
-                       highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
+                       highdm = subsurf_dm_create_local(
+                               scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+                               has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
                        ss = ((CCGDerivedMesh *)highdm)->ss;
 
                        /* create multires DM from original mesh and displacements */
-                       lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask);
+                       lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
                        cddm->release(cddm);
 
                        /* gather grid data */
@@ -1286,7 +1295,9 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
                        else cddm = CDDM_from_mesh(me);
                        DM_set_only_copy(cddm, CD_MASK_BAREMESH);
 
-                       subdm = subsurf_dm_create_local(scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
+                       subdm = subsurf_dm_create_local(
+                               scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+                               has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
                        cddm->release(cddm);
 
                        multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
@@ -1374,11 +1385,13 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
        if (lvl == 0)
                return dm;
 
+       const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0;
+
        result = subsurf_dm_create_local(scene, ob, dm, lvl,
                                         mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges,
                                         mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
                                         flags & MULTIRES_ALLOC_PAINT_MASK,
-                                        render);
+                                        render, subsurf_flags);
 
        if (!(flags & MULTIRES_USE_LOCAL_MMD)) {
                ccgdm = (CCGDerivedMesh *)result;
index d51cde49072570785c16f986ff4e754b9829187a..b1c4102df83626b9a35a0451b31cacf3a00482bb 100644 (file)
@@ -2873,17 +2873,20 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
         float (*vertCos)[3],
         SubsurfFlags flags)
 {
-       int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
-       CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
-       int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
-       int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
+       const int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
+       const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
+       const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
+       const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
+       const bool use_gpu_backend = subsurf_use_gpu_backend(flags);
+       const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY);
        CCGDerivedMesh *result;
-       bool use_gpu_backend = subsurf_use_gpu_backend(flags);
 
        /* note: editmode calculation can only run once per
         * modifier stack evaluation (uses freed cache) [#36299] */
        if (flags & SUBSURF_FOR_EDIT_MODE) {
-               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
+               int levels = (scene != NULL && !ignore_simplify)
+                       ? get_render_subsurf_level(&scene->r, smd->levels, false)
+                       : smd->levels;
 
                /* TODO(sergey): Same as emCache below. */
                if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
@@ -2904,7 +2907,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        else if (flags & SUBSURF_USE_RENDER_PARAMS) {
                /* Do not use cache in render mode. */
                CCGSubSurf *ss;
-               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels;
+               int levels = (scene != NULL && !ignore_simplify)
+                       ? get_render_subsurf_level(&scene->r, smd->renderLevels, true)
+                       : smd->renderLevels;
 
                if (levels == 0)
                        return dm;
@@ -2920,7 +2925,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        }
        else {
                int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
-               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
+               int levels = (scene != NULL && !ignore_simplify)
+                       ? get_render_subsurf_level(&scene->r, smd->levels, false)
+                       : smd->levels;
                CCGSubSurf *ss;
 
                /* It is quite possible there is a much better place to do this. It