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.
This commit is contained in:
parent
f76f48be23
commit
73dc8c24e4
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue