diff options
author | Campbell Barton <campbell@blender.org> | 2022-03-08 14:07:59 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-03-08 14:15:12 +0300 |
commit | 73dc8c24e44ba8b462f88c1c629a84c98979ef41 (patch) | |
tree | 4b3cb93544a04a319ac79b8bf91e94cb76c201af /source | |
parent | f76f48be23e04dbbbe313e428636cfcbcf2be59c (diff) |
PyAPI: optimize depsgraph use in PyDrivers
Avoid re-creating & freeing the depsgraph for every driver evaluation.
Now the depsgraph is kept in the name-space (matching self),
only re-created when the value changes.
In a contrived test-case with many drivers this gave ~15% overall
speedup for animation playback.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/python/intern/bpy_driver.c | 74 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_intern_string.c | 4 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_intern_string.h | 1 |
3 files changed, 41 insertions, 38 deletions
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index e2b6b2bec29..68018d22753 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -162,9 +162,11 @@ static struct { /* borrowed reference to the 'self' in 'bpy_pydriver_Dict' * keep for as long as the same self is used. */ PyObject *self; + BPy_StructRNA *depsgraph; } g_pydriver_state_prev = { .evaltime = FLT_MAX, .self = NULL, + .depsgraph = NULL, }; static void bpy_pydriver_namespace_update_frame(const float evaltime) @@ -199,6 +201,38 @@ static void bpy_pydriver_namespace_clear_self(void) } } +static PyObject *bpy_pydriver_depsgraph_as_pyobject(struct Depsgraph *depsgraph) +{ + struct PointerRNA depsgraph_ptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr); + return pyrna_struct_CreatePyObject(&depsgraph_ptr); +} + +/** + * Adds a variable 'depsgraph' to the name-space. This can then be used to obtain evaluated + * data-blocks, and the current view layer and scene. See T75553. + */ +static void bpy_pydriver_namespace_update_depsgraph(struct Depsgraph *depsgraph) +{ + /* This should never happen, but it's probably better to have None in Python + * than a NULL-wrapping Depsgraph Python struct. */ + BLI_assert(depsgraph != NULL); + if (UNLIKELY(depsgraph == NULL)) { + PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_depsgraph, Py_None); + g_pydriver_state_prev.depsgraph = NULL; + return; + } + + if ((g_pydriver_state_prev.depsgraph == NULL) || + ((depsgraph != g_pydriver_state_prev.depsgraph->ptr.data))) { + PyObject *item = bpy_pydriver_depsgraph_as_pyobject(depsgraph); + PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_depsgraph, item); + Py_DECREF(item); + + g_pydriver_state_prev.depsgraph = (BPy_StructRNA *)item; + } +} + void BPY_driver_reset(void) { PyGILState_STATE gilstate; @@ -226,6 +260,7 @@ void BPY_driver_reset(void) /* freed when clearing driver dict */ g_pydriver_state_prev.self = NULL; + g_pydriver_state_prev.depsgraph = NULL; if (use_gil) { PyGILState_Release(gilstate); @@ -369,41 +404,6 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d } #endif /* USE_BYTECODE_WHITELIST */ - -static PyObject *bpy_pydriver_depsgraph_as_pyobject(struct Depsgraph *depsgraph) -{ - /* This should never happen, but it's probably better to have None in Python - * than a NULL-wrapping Depsgraph py struct. */ - BLI_assert(depsgraph != NULL); - if (depsgraph == NULL) { - Py_RETURN_NONE; - } - - struct PointerRNA depsgraph_ptr; - RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr); - return pyrna_struct_CreatePyObject(&depsgraph_ptr); -} - -/** - * Adds a variable 'depsgraph' to the driver variables. This can then be used to obtain evaluated - * data-blocks, and the current view layer and scene. See T75553. - */ -static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars, - struct Depsgraph *depsgraph) -{ - PyObject *py_depsgraph = bpy_pydriver_depsgraph_as_pyobject(depsgraph); - const char *depsgraph_variable_name = "depsgraph"; - - if (PyDict_SetItemString(driver_vars, depsgraph_variable_name, py_depsgraph) == -1) { - fprintf(stderr, - "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", - depsgraph_variable_name); - PyErr_Print(); - PyErr_Clear(); - } - Py_DECREF(py_depsgraph); -} - float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, @@ -489,6 +489,8 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, bpy_pydriver_namespace_clear_self(); } + bpy_pydriver_namespace_update_depsgraph(anim_eval_context->depsgraph); + if (driver_orig->expr_comp == NULL) { driver_orig->flag |= DRIVER_FLAG_RECOMPILE; } @@ -613,8 +615,6 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, } #endif /* USE_BYTECODE_WHITELIST */ - bpy_pydriver_namespace_add_depsgraph(driver_vars, anim_eval_context->depsgraph); - #if 0 /* slow, with this can avoid all Py_CompileString above. */ /* execute expression to get a value */ retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars); diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c index 1cf8f3b65a0..817494cb70a 100644 --- a/source/blender/python/intern/bpy_intern_string.c +++ b/source/blender/python/intern/bpy_intern_string.c @@ -14,7 +14,7 @@ #include "BLI_utildefines.h" -static PyObject *bpy_intern_str_arr[16]; +static PyObject *bpy_intern_str_arr[17]; PyObject *bpy_intern_str___annotations__; PyObject *bpy_intern_str___doc__; @@ -31,6 +31,7 @@ PyObject *bpy_intern_str_frame; PyObject *bpy_intern_str_properties; PyObject *bpy_intern_str_register; PyObject *bpy_intern_str_self; +PyObject *bpy_intern_str_depsgraph; PyObject *bpy_intern_str_unregister; void bpy_intern_string_init(void) @@ -58,6 +59,7 @@ void bpy_intern_string_init(void) BPY_INTERN_STR(bpy_intern_str_properties, "properties"); BPY_INTERN_STR(bpy_intern_str_register, "register"); BPY_INTERN_STR(bpy_intern_str_self, "self"); + BPY_INTERN_STR(bpy_intern_str_depsgraph, "depsgraph"); BPY_INTERN_STR(bpy_intern_str_unregister, "unregister"); #undef BPY_INTERN_STR diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h index 1d74e8c31c5..cc8bf8a6f3b 100644 --- a/source/blender/python/intern/bpy_intern_string.h +++ b/source/blender/python/intern/bpy_intern_string.h @@ -28,6 +28,7 @@ extern PyObject *bpy_intern_str_frame; extern PyObject *bpy_intern_str_properties; extern PyObject *bpy_intern_str_register; extern PyObject *bpy_intern_str_self; +extern PyObject *bpy_intern_str_depsgraph; extern PyObject *bpy_intern_str_unregister; #ifdef __cplusplus |