Fix #34783: smoke simulation crash when changing frame while preview rendering.
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 24 Apr 2013 17:31:09 +0000 (17:31 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 24 Apr 2013 17:31:09 +0000 (17:31 +0000)
Added a mutex lock for smoke data access. The render was already working with a
copy of the volume data, so it's just a short lock to copy things and should not
block the UI much.

source/blender/blenkernel/intern/smoke.c
source/blender/blenlib/BLI_threads.h
source/blender/blenlib/intern/threads.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_smoke_types.h
source/blender/render/intern/source/voxeldata.c

index 009112be2c9d5a394c13980dc26ee182e82f2c04..f31a672c664bc299d22fa524e9f7b3e62432674d 100644 (file)
@@ -50,6 +50,7 @@
 #include "BLI_edgehash.h"
 #include "BLI_kdtree.h"
 #include "BLI_kdopbvh.h"
+#include "BLI_threads.h"
 #include "BLI_utildefines.h"
 #include "BLI_voxel.h"
 
@@ -365,6 +366,9 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
                if (smd->domain->fluid)
                        smoke_free(smd->domain->fluid);
 
+               if (smd->domain->fluid_mutex)
+                       BLI_rw_mutex_free(smd->domain->fluid_mutex);
+
                if (smd->domain->wt)
                        smoke_turbulence_free(smd->domain->wt);
 
@@ -436,8 +440,12 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
 
                        if (smd->domain->fluid)
                        {
+                               BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
                                smoke_free(smd->domain->fluid);
                                smd->domain->fluid = NULL;
+
+                               BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
                        }
 
                        smokeModifier_reset_turbulence(smd);
@@ -497,6 +505,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->ptcaches[1].first = smd->domain->ptcaches[1].last = NULL;
                        /* set some standard values */
                        smd->domain->fluid = NULL;
+                       smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
                        smd->domain->wt = NULL;
                        smd->domain->eff_group = NULL;
                        smd->domain->fluid_group = NULL;
@@ -2316,8 +2325,15 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
 
 struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
 {
+       /* lock so preview render does not read smoke data while it gets modified */
+       if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+               BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
        smokeModifier_process(smd, scene, ob, dm);
 
+       if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+               BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
+
        /* return generated geometry for adaptive domain */
        if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
            smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN &&
index ec8e567c0efd4f20f3745493739947408a5368ba..614cd4ee59dfc7eba1185832229880eb272ef133 100644 (file)
@@ -92,9 +92,13 @@ typedef pthread_mutex_t ThreadMutex;
 #define BLI_MUTEX_INITIALIZER   PTHREAD_MUTEX_INITIALIZER
 
 void BLI_mutex_init(ThreadMutex *mutex);
+void BLI_mutex_end(ThreadMutex *mutex);
+
+ThreadMutex *BLI_mutex_alloc(void);
+void BLI_mutex_free(ThreadMutex *mutex);
+
 void BLI_mutex_lock(ThreadMutex *mutex);
 void BLI_mutex_unlock(ThreadMutex *mutex);
-void BLI_mutex_end(ThreadMutex *mutex);
 
 /* Spin Lock */
 
@@ -117,9 +121,13 @@ void BLI_spin_end(SpinLock *spin);
 typedef pthread_rwlock_t ThreadRWMutex;
 
 void BLI_rw_mutex_init(ThreadRWMutex *mutex);
+void BLI_rw_mutex_end(ThreadRWMutex *mutex);
+
+ThreadRWMutex *BLI_rw_mutex_alloc(void);
+void BLI_rw_mutex_free(ThreadRWMutex *mutex);
+
 void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode);
 void BLI_rw_mutex_unlock(ThreadRWMutex *mutex);
-void BLI_rw_mutex_end(ThreadRWMutex *mutex);
 
 /* ThreadedWorker
  *
index 1d3312fafb1bb02139b7f927b6de4726aa7d380b..8b1ba38a35a8dffb18438761c99ae962b79102c2 100644 (file)
@@ -399,6 +399,19 @@ void BLI_mutex_end(ThreadMutex *mutex)
        pthread_mutex_destroy(mutex);
 }
 
+ThreadMutex *BLI_mutex_alloc(void)
+{
+       ThreadMutex *mutex = MEM_callocN(sizeof(ThreadMutex), "ThreadMutex");
+       BLI_mutex_init(mutex);
+       return mutex;
+}
+
+void BLI_mutex_free(ThreadMutex *mutex)
+{
+       BLI_mutex_end(mutex);
+       MEM_freeN(mutex);
+}
+
 /* Spin Locks */
 
 void BLI_spin_init(SpinLock *spin)
@@ -464,6 +477,19 @@ void BLI_rw_mutex_end(ThreadRWMutex *mutex)
        pthread_rwlock_destroy(mutex);
 }
 
+ThreadRWMutex *BLI_rw_mutex_alloc(void)
+{
+       ThreadRWMutex *mutex = MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex");
+       BLI_rw_mutex_init(mutex);
+       return mutex;
+}
+
+void BLI_rw_mutex_free(ThreadRWMutex *mutex)
+{
+       BLI_rw_mutex_end(mutex);
+       MEM_freeN(mutex);
+}
+
 /* ************************************************ */
 
 typedef struct ThreadedWorker {
index 466c0b6dcb2720a5f22421edc8b00bafb7369e81..a2e97e8063c93b7c40fecd1fc02a358570f996e6 100644 (file)
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
 #include "BLI_edgehash.h"
+#include "BLI_threads.h"
 
 #include "BLF_translation.h"
 
@@ -4595,6 +4596,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
                                smd->domain->smd = smd;
                                
                                smd->domain->fluid = NULL;
+                               smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
                                smd->domain->wt = NULL;
                                smd->domain->shadow = NULL;
                                smd->domain->tex = NULL;
index 76ba3fcf7f86f95fa4c2a396c4df17576131f6c9..fa31717b9e2f005af8868d08a4c6f9184183da72 100644 (file)
@@ -71,6 +71,7 @@
 typedef struct SmokeDomainSettings {
        struct SmokeModifierData *smd; /* for fast RNA access */
        struct FLUID_3D *fluid;
+       void *fluid_mutex;
        struct Group *fluid_group;
        struct Group *eff_group; // UNUSED
        struct Group *coll_group; // collision objects group
index 9990ad7e900054152c773fb9a50aec247c7fae51..1c76a2285667a43318f65959bee2e9320bbb8cf2 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
+#include "BLI_threads.h"
 #include "BLI_voxel.h"
 #include "BLI_utildefines.h"
 
@@ -239,6 +240,13 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
                SmokeDomainSettings *sds = smd->domain;
                
                if (sds && sds->fluid) {
+                       BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+                       if (!sds->fluid) {
+                               BLI_rw_mutex_unlock(sds->fluid_mutex);
+                               return;
+                       }
+
                        if (cfra < sds->point_cache[0]->startframe)
                                ;  /* don't show smoke before simulation starts, this could be made an option in the future */
                        else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
@@ -246,7 +254,10 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
                                size_t i;
                                float *heat;
 
-                               if (!smoke_has_heat(sds->fluid)) return;
+                               if (!smoke_has_heat(sds->fluid)) {
+                                       BLI_rw_mutex_unlock(sds->fluid_mutex);
+                                       return;
+                               }
 
                                copy_v3_v3_int(vd->resol, sds->res);
                                totRes = vd_resol_size(vd);
@@ -283,12 +294,18 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
                                float *flame;
 
                                if (sds->flags & MOD_SMOKE_HIGHRES) {
-                                       if (!smoke_turbulence_has_fuel(sds->wt)) return;
+                                       if (!smoke_turbulence_has_fuel(sds->wt)) {
+                                               BLI_rw_mutex_unlock(sds->fluid_mutex);
+                                               return;
+                                       }
                                        smoke_turbulence_get_res(sds->wt, vd->resol);
                                        flame = smoke_turbulence_get_flame(sds->wt);
                                }
                                else {
-                                       if (!smoke_has_fuel(sds->fluid)) return;
+                                       if (!smoke_has_fuel(sds->fluid)) {
+                                               BLI_rw_mutex_unlock(sds->fluid_mutex);
+                                               return;
+                                       }
                                        copy_v3_v3_int(vd->resol, sds->res);
                                        flame = smoke_get_flame(sds->fluid);
                                }
@@ -333,6 +350,8 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
                                        }
                                }
                        }  /* end of fluid condition */
+
+                       BLI_rw_mutex_unlock(sds->fluid_mutex);
                }
        }