Fix T38403: Laplacian smooth on instanced objects leads to crash.
authorLukas Tönne <lukas.toenne@gmail.com>
Thu, 30 Jan 2014 12:06:48 +0000 (13:06 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Thu, 30 Jan 2014 12:09:32 +0000 (13:09 +0100)
The laplacian modifiers (smooth and deform) use the OpenNL library,
which is not threadsafe due to the use of a global context variable.
Ideally this would be changed so that an explicit context can be
created for every caller of the OpenNL functions, but since OpenNL's
most recent version is from 2010 this is unlikely to happen.

As a workaround for now just use a mutex to prevent conflicting OpenNL
calls. Eventually OpenNL can be replaced by eigen or ceres.

source/blender/modifiers/intern/MOD_laplaciandeform.c
source/blender/modifiers/intern/MOD_laplaciansmooth.c
source/blender/modifiers/intern/MOD_util.c
source/blender/modifiers/intern/MOD_util.h

index defd287034eedde7f91742c99b1e3068e0067bdf..7b5b73e0f6d803de9db5647806d73a6644326f5b 100644 (file)
@@ -452,6 +452,10 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
        n = sys->total_verts;
        na = sys->total_anchors;
 
+#ifdef OPENNL_THREADING_HACK
+       modifier_opennl_lock();
+#endif
+
        if (!sys->is_matrix_computed) {
                nlNewContext();
                sys->context = nlGetCurrent();
@@ -530,12 +534,9 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
                        sys->has_solution = false;
                }
                sys->is_matrix_computed = true;
-       }
-       else {
-               if (!sys->has_solution) {
-                       return;
-               }
 
+       }
+       else if (sys->has_solution) {
                nlBegin(NL_SYSTEM);
                nlBegin(NL_MATRIX);
 
@@ -589,6 +590,10 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
                        sys->has_solution = false;
                }
        }
+
+#ifdef OPENNL_THREADING_HACK
+       modifier_opennl_unlock();
+#endif
 }
 
 static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm)
index febd81e2f1b1b498feefd096435f1f7fb619cd5a..130013af75bf8d9c0270bd0d227f843fc2fb063e 100644 (file)
@@ -534,6 +534,11 @@ static void laplaciansmoothModifier_do(
        sys->vert_centroid[1] = 0.0f;
        sys->vert_centroid[2] = 0.0f;
        memset_laplacian_system(sys, 0);
+
+#ifdef OPENNL_THREADING_HACK
+       modifier_opennl_lock();
+#endif
+
        nlNewContext();
        sys->context = nlGetCurrent();
        nlSolverParameteri(NL_NB_VARIABLES, numVerts);
@@ -618,6 +623,11 @@ static void laplaciansmoothModifier_do(
        }
        nlDeleteContext(sys->context);
        sys->context = NULL;
+
+#ifdef OPENNL_THREADING_HACK
+       modifier_opennl_unlock();
+#endif
+
        delete_laplacian_system(sys);
 }
 
index feae95bf777fa33a969d8d496da4c85803b48ebb..0cc9b8bb77b8d4dd3fe63a864068e7d35e647342 100644 (file)
 
 #include "RE_shader_ext.h"
 
+#ifdef OPENNL_THREADING_HACK
+#include "BLI_threads.h"
+#endif
+
 void modifier_init_texture(Scene *scene, Tex *tex)
 {
        if (!tex)
@@ -235,6 +239,24 @@ void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformV
        }
 }
 
+
+#ifdef OPENNL_THREADING_HACK
+
+static ThreadMutex opennl_context_mutex = BLI_MUTEX_INITIALIZER;
+
+void modifier_opennl_lock(void)
+{
+       BLI_mutex_lock(&opennl_context_mutex);
+}
+
+void modifier_opennl_unlock(void)
+{
+       BLI_mutex_unlock(&opennl_context_mutex);
+}
+
+#endif
+
+
 /* only called by BKE_modifier.h/modifier.c */
 void modifier_type_init(ModifierTypeInfo *types[])
 {
index 72077b5c0008d0a2bb55c4b440d7b9377fdd8820..cb851a51c641fa2b4d8bd5b483ef108399bc2bf9 100644 (file)
@@ -52,4 +52,21 @@ struct DerivedMesh *get_dm_for_modifier(struct Object *ob, ModifierApplyFlag fla
 void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm,
                          const char *name, struct MDeformVert **dvert, int *defgrp_index);
 
+/* XXX workaround for non-threadsafe context in OpenNL (T38403)
+ * OpenNL uses global pointer for "current context", which causes
+ * conflict when multiple modifiers get evaluated in threaded depgraph.
+ * This is just a stupid hack to prevent assert failure / crash,
+ * otherwise we'd have to modify OpenNL on a large scale.
+ * OpenNL should be replaced eventually, there are other options (eigen, ceres).
+ * - lukas_t
+ */
+#ifdef WITH_OPENNL
+#define OPENNL_THREADING_HACK
+#endif
+
+#ifdef OPENNL_THREADING_HACK
+void modifier_opennl_lock(void);
+void modifier_opennl_unlock(void);
+#endif
+
 #endif /* __MOD_UTIL_H__ */