[Bf-blender-cvs] [73dc8c24e44] master: PyAPI: optimize depsgraph use in PyDrivers

Campbell Barton noreply at git.blender.org
Tue Mar 8 12:17:50 CET 2022


Commit: 73dc8c24e44ba8b462f88c1c629a84c98979ef41
Author: Campbell Barton
Date:   Tue Mar 8 22:07:59 2022 +1100
Branches: master
https://developer.blender.org/rB73dc8c24e44ba8b462f88c1c629a84c98979ef41

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.

===================================================================

M	source/blender/python/intern/bpy_driver.c
M	source/blender/python/intern/bpy_intern_string.c
M	source/blender/python/intern/bpy_intern_string.h

===================================================================

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



More information about the Bf-blender-cvs mailing list