From dbeec2be86db5b4ba440175e59c52ff84eb98462 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 24 Apr 2013 17:31:09 +0000 Subject: Fix #34783: smoke simulation crash when changing frame while preview rendering. 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 | 16 +++++++++++++++ source/blender/blenlib/BLI_threads.h | 12 ++++++++++-- source/blender/blenlib/intern/threads.c | 26 +++++++++++++++++++++++++ source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_smoke_types.h | 1 + source/blender/render/intern/source/voxeldata.c | 25 +++++++++++++++++++++--- 6 files changed, 77 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 009112be2c9..f31a672c664 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -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 && diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index ec8e567c0ef..614cd4ee59d 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -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 * diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index 1d3312fafb1..8b1ba38a35a 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -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 { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 466c0b6dcb2..a2e97e8063c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -107,6 +107,7 @@ #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; diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 76ba3fcf7f8..fa31717b9e2 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -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 diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 9990ad7e900..1c76a228566 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -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); } } -- cgit v1.2.3