diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 09f5ecce050..dbe325b2056 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -108,7 +108,8 @@ bool driver_get_variable_property( struct ChannelDriver *driver, struct DriverTarget *dtar, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); -float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); +float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, + struct ChannelDriver *driver_orig, const float evaltime); /* ************** F-Curve Modifiers *************** */ @@ -282,7 +283,8 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]); /* evaluate fcurve */ float evaluate_fcurve(struct FCurve *fcu, float evaltime); -float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); +float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, + struct ChannelDriver *driver_orig, float evaltime); /* evaluate fcurve and store value */ float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index e5a68fa7476..0867170611f 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -3017,7 +3017,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, PathResolvedRNA anim_rna; if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { const float ctime = DEG_get_ctime(depsgraph); - const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime); ok = animsys_write_rna_setting(&anim_rna, curval); if (ok && DEG_is_active(depsgraph)) { animsys_write_orig_anim_rna(&id_ptr, NULL, fcu, curval); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 0de04e31be9..0ffc9054ddd 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1922,13 +1922,14 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) /* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" * - "evaltime" is the frame at which F-Curve is being evaluated * - has to return a float value + * - driver_orig is where we cache Python expressions, in case of COW */ -float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) +float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime) { DriverVar *dvar; /* check if driver can be evaluated */ - if (driver->flag & DRIVER_FLAG_INVALID) + if (driver_orig->flag & DRIVER_FLAG_INVALID) return 0.0f; switch (driver->type) { @@ -1998,8 +1999,8 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl { #ifdef WITH_PYTHON /* check for empty or invalid expression */ - if ( (driver->expression[0] == '\0') || - (driver->flag & DRIVER_FLAG_INVALID) ) + if ( (driver_orig->expression[0] == '\0') || + (driver_orig->flag & DRIVER_FLAG_INVALID) ) { driver->curval = 0.0f; } @@ -2009,7 +2010,7 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl */ BLI_mutex_lock(&python_driver_lock); - driver->curval = BPY_driver_exec(anim_rna, driver, evaltime); + driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); BLI_mutex_unlock(&python_driver_lock); } @@ -2705,7 +2706,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) return evaluate_fcurve_ex(fcu, evaltime, 0.0); } -float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) +float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime) { BLI_assert(fcu->driver != NULL); float cvalue = 0.0f; @@ -2715,7 +2716,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evalt */ if (fcu->driver) { /* evaltime now serves as input for the curve */ - evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime); + evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime); /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { @@ -2762,7 +2763,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) /* calculate and set curval (evaluates driver too if necessary) */ float curval; if (fcu->driver) { - curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime); + curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime); } else { curval = evaluate_fcurve(fcu, evaltime); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 1913eb944d9..fe5714aba2e 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -954,7 +954,7 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) { /* for making it easier to add corrective drivers... */ - cfra = evaluate_driver(&anim_rna, fcu->driver, cfra); + cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra); } else { cfra = 0.0f; diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index b4c36a7c516..da1b031f1c0 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -87,7 +87,8 @@ void BPY_modules_load_user(struct bContext *C); void BPY_app_handlers_reset(const short do_all); void BPY_driver_reset(void); -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, + struct ChannelDriver *driver_orig, const float evaltime); void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr); diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 215a64a4449..96bfa9f26d3 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -48,6 +48,8 @@ #include "bpy_driver.h" +#include "BPY_extern.h" + extern void BPY_update_rna_module(void); #define USE_RNA_AS_PYOBJECT @@ -196,8 +198,12 @@ static void pydriver_error(ChannelDriver *driver) * (new)note: checking if python is running is not threadsafe [#28114] * now release the GIL on python operator execution instead, using * PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender. + * + * For copy-on-write we always cache expressions and write errors in the + * original driver, otherwise these would get freed while editing. Due to + * the GIL this is thread-safe. */ -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime) { PyObject *driver_vars = NULL; PyObject *retval = NULL; @@ -213,7 +219,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c int i; /* get the py expression to be evaluated */ - expr = driver->expression; + expr = driver_orig->expression; if (expr[0] == '\0') return 0.0f; @@ -249,47 +255,47 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c /* update global namespace */ bpy_pydriver_namespace_update_frame(evaltime); - if (driver->flag & DRIVER_FLAG_USE_SELF) { + if (driver_orig->flag & DRIVER_FLAG_USE_SELF) { bpy_pydriver_namespace_update_self(anim_rna); } else { bpy_pydriver_namespace_clear_self(); } - if (driver->expr_comp == NULL) - driver->flag |= DRIVER_FLAG_RECOMPILE; + if (driver_orig->expr_comp == NULL) + driver_orig->flag |= DRIVER_FLAG_RECOMPILE; /* compile the expression first if it hasn't been compiled or needs to be rebuilt */ - if (driver->flag & DRIVER_FLAG_RECOMPILE) { - Py_XDECREF(driver->expr_comp); - driver->expr_comp = PyTuple_New(2); + if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) { + Py_XDECREF(driver_orig->expr_comp); + driver_orig->expr_comp = PyTuple_New(2); expr_code = Py_CompileString(expr, "", Py_eval_input); - PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, expr_code); + PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code); - driver->flag &= ~DRIVER_FLAG_RECOMPILE; - driver->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */ + driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE; + driver_orig->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */ } else { - expr_code = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 0); + expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0); } - if (driver->flag & DRIVER_FLAG_RENAMEVAR) { + if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) { /* may not be set */ - expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1); + expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1); Py_XDECREF(expr_vars); - expr_vars = PyTuple_New(BLI_listbase_count(&driver->variables)); - PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 1, expr_vars); + expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables)); + PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars); - for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) { + for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) { PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name)); } - driver->flag &= ~DRIVER_FLAG_RENAMEVAR; + driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR; } else { - expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1); + expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1); } /* add target values to a dict that will be used as '__locals__' dict */ diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h index 017a6fe89c5..971cbdf901f 100644 --- a/source/blender/python/intern/bpy_driver.h +++ b/source/blender/python/intern/bpy_driver.h @@ -27,14 +27,7 @@ #ifndef __BPY_DRIVER_H__ #define __BPY_DRIVER_H__ -struct ChannelDriver; -struct PathResolvedRNA; - int bpy_pydriver_create_dict(void); extern PyObject *bpy_pydriver_Dict; -/* externals */ -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); -void BPY_driver_reset(void); - #endif /* __BPY_DRIVER_H__ */