Fix T47971: rigid body baking crash due to thread race condition.

This commit is contained in:
Brecht Van Lommel 2016-04-02 04:24:24 +02:00
parent b03ff0bbf8
commit 74e40663da
4 changed files with 93 additions and 91 deletions

@ -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;

@ -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) {

@ -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;
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;
}
}
BLI_freelistN(&pidlist);
}
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 = baker;
job->ob = NULL;
job->pidlist.first = NULL;
job->pidlist.last = NULL;
job->baker = ptcache_baker_create(C, op, all);
job->baker->bake_job = job;
job->baker->update_progress = ptcache_job_update;
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);
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;

@ -3074,15 +3074,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);
}