diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-04-02 05:24:24 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2016-04-05 11:36:14 +0300 |
commit | 45e68e190dca949d4d2018d587b8f3cbb1000700 (patch) | |
tree | 360ed65646d260410dfa7a7f30da4aa1dfd2bbdd /source/blender | |
parent | 754566cf5bfb795a9b38312a8e6edce4e0045827 (diff) |
Fix T47971: rigid body baking crash due to thread race condition.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 18 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_pointcache.c | 160 | ||||
-rw-r--r-- | source/blender/render/intern/source/pipeline.c | 4 |
4 files changed, 93 insertions, 91 deletions
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 40dbffe7222..8238ea64242 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -190,7 +190,7 @@ typedef struct PTCacheBaker { int render; int anim_init; int quick_step; - struct PTCacheID *pid; + struct PTCacheID pid; void (*update_progress)(void *data, float progress, int *cancel); void *bake_job; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index c8a42d81f1d..448aaaa7830 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3508,15 +3508,13 @@ void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene) { PTCacheBaker baker; - baker.bake=0; - baker.pid=NULL; - baker.render=0; + memset(&baker, 0, sizeof(baker)); + baker.main = bmain; + baker.scene = scene; + baker.bake = 0; + baker.render = 0; baker.anim_init = 0; - baker.main=bmain; - baker.scene=scene; - baker.quick_step=scene->physics_settings.quick_cache_step; - baker.update_progress = NULL; - baker.bake_job = NULL; + baker.quick_step = scene->physics_settings.quick_cache_step; BKE_ptcache_bake(&baker); } @@ -3541,7 +3539,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) Scene *sce_iter; /* SETLOOPER macro only */ Base *base; ListBase pidlist; - PTCacheID *pid = baker->pid; + PTCacheID *pid = &baker->pid; PointCache *cache = NULL; float frameleno = scene->r.framelen; int cfrao = CFRA; @@ -3552,7 +3550,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) G.is_break = false; /* set caches to baking mode and figure out start frame */ - if (pid) { + if (pid->ob) { /* cache/bake a single object */ cache = pid->cache; if ((cache->flag & PTCACHE_BAKED)==0) { diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index 406b5892234..e81aa584586 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -30,6 +30,7 @@ */ #include <stdlib.h> +#include <string.h> #include "MEM_guardedalloc.h" @@ -57,12 +58,7 @@ static int ptcache_bake_all_poll(bContext *C) { - Scene *scene= CTX_data_scene(C); - - if (!scene) - return 0; - - return 1; + return CTX_data_scene(C) != NULL; } static int ptcache_poll(bContext *C) @@ -77,14 +73,11 @@ typedef struct PointCacheJob { float *progress; PTCacheBaker *baker; - Object *ob; - ListBase pidlist; } PointCacheJob; static void ptcache_job_free(void *customdata) { PointCacheJob *job = customdata; - BLI_freelistN(&job->pidlist); MEM_freeN(job->baker); MEM_freeN(job); } @@ -149,7 +142,7 @@ static void ptcache_job_endjob(void *customdata) WM_set_locked_interface(G.main->wm.first, false); WM_main_add_notifier(NC_SCENE | ND_FRAME, scene); - WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->ob); + WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob); } static void ptcache_free_bake(PointCache *cache) @@ -166,32 +159,60 @@ static void ptcache_free_bake(PointCache *cache) } } -static int ptcache_bake_all_exec(bContext *C, wmOperator *op) +static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker"); - PTCacheBaker *baker = MEM_mallocN(sizeof(PTCacheBaker), "PTCacheBaker"); - - baker->main = bmain; - baker->scene = scene; - baker->pid = NULL; + baker->main = CTX_data_main(C); + baker->scene = CTX_data_scene(C); baker->bake = RNA_boolean_get(op->ptr, "bake"); baker->render = 0; baker->anim_init = 0; baker->quick_step = 1; - baker->update_progress = ptcache_job_update; - PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob"); - job->baker = baker; - job->ob = NULL; - job->pidlist.first = NULL; - job->pidlist.last = NULL; + if (!all) { + PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); + Object *ob = ptr.id.data; + PointCache *cache = ptr.data; + + ListBase pidlist; + BKE_ptcache_ids_from_object(&pidlist, ob, baker->scene, MAX_DUPLI_RECUR); + + for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) { + if (pid->cache == cache) { + baker->pid = *pid; + break; + } + } - baker->bake_job = job; + BLI_freelistN(&pidlist); + } - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Point Cache", - WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE); + return baker; +} + +static int ptcache_bake_exec(bContext *C, wmOperator *op) +{ + bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all"); + + PTCacheBaker *baker = ptcache_baker_create(C, op, all); + BKE_ptcache_bake(baker); + MEM_freeN(baker); + + return OPERATOR_FINISHED; +} + +static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all"); + + PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob"); + job->baker = ptcache_baker_create(C, op, all); + job->baker->bake_job = job; + job->baker->update_progress = ptcache_job_update; + + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C), + "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE); WM_jobs_customdata_set(wm_job, job, ptcache_job_free); WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE); @@ -201,7 +222,33 @@ static int ptcache_bake_all_exec(bContext *C, wmOperator *op) WM_jobs_start(CTX_wm_manager(C), wm_job); - return OPERATOR_FINISHED; + WM_event_add_modal_handler(C, op); + + /* we must run modal until the bake job is done, otherwise the undo push + * happens before the job ends, which can lead to race conditions between + * the baking and file writing code */ + return OPERATOR_RUNNING_MODAL; +} + +static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Scene *scene = (Scene *) op->customdata; + + /* no running blender, remove handler and pass through */ + if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + + return OPERATOR_PASS_THROUGH; +} + +static void ptcache_bake_cancel(bContext *C, wmOperator *op) +{ + wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = (Scene *) op->customdata; + + /* kill on cancel, because job is using op->reports */ + WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_POINTCACHE); } static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op)) @@ -236,7 +283,10 @@ void PTCACHE_OT_bake_all(wmOperatorType *ot) ot->idname = "PTCACHE_OT_bake_all"; /* api callbacks */ - ot->exec = ptcache_bake_all_exec; + ot->exec = ptcache_bake_exec; + ot->invoke = ptcache_bake_invoke; + ot->modal = ptcache_bake_modal; + ot->cancel = ptcache_bake_cancel; ot->poll = ptcache_bake_all_poll; /* flags */ @@ -259,53 +309,6 @@ void PTCACHE_OT_free_bake_all(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } -static int ptcache_bake_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); - Object *ob = ptr.id.data; - PointCache *cache = ptr.data; - - PTCacheBaker *baker = MEM_mallocN(sizeof(PTCacheBaker), "PTCacheBaker"); - baker->main = bmain; - baker->scene = scene; - baker->bake = RNA_boolean_get(op->ptr, "bake"); - baker->render = 0; - baker->anim_init = 0; - baker->quick_step = 1; - baker->update_progress = ptcache_job_update; - baker->pid = NULL; - - PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob"); - job->baker = baker; - job->ob = ob; - - BKE_ptcache_ids_from_object(&job->pidlist, ob, scene, MAX_DUPLI_RECUR); - - for (PTCacheID *pid = job->pidlist.first; pid; pid = pid->next) { - if (pid->cache == cache) { - baker->pid = pid; - break; - } - } - - baker->bake_job = job; - - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Point Cache", - WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE); - - WM_jobs_customdata_set(wm_job, job, ptcache_job_free); - WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE); - WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob); - - WM_set_locked_interface(CTX_wm_manager(C), true); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - - return OPERATOR_FINISHED; -} - static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); @@ -339,6 +342,9 @@ void PTCACHE_OT_bake(wmOperatorType *ot) /* api callbacks */ ot->exec = ptcache_bake_exec; + ot->invoke = ptcache_bake_invoke; + ot->modal = ptcache_bake_modal; + ot->cancel = ptcache_bake_cancel; ot->poll = ptcache_poll; /* flags */ @@ -441,7 +447,7 @@ void PTCACHE_OT_add(wmOperatorType *ot) /* api callbacks */ ot->exec = ptcache_add_new_exec; - ot->poll = ptcache_poll; // ptcache_bake_all_poll; + ot->poll = ptcache_poll; /* flags */ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 6fef581e0ed..f7e35a48022 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3061,15 +3061,13 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init) { PTCacheBaker baker; + memset(&baker, 0, sizeof(baker)); baker.main = re->main; baker.scene = scene; - baker.pid = NULL; baker.bake = 0; baker.render = 1; baker.anim_init = 1; baker.quick_step = 1; - baker.update_progress = NULL; - baker.bake_job = NULL; BKE_ptcache_bake(&baker); } |