Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorNathan Letwory <nathan@letworyinteractive.com>2008-02-23 15:05:28 +0300
committerNathan Letwory <nathan@letworyinteractive.com>2008-02-23 15:05:28 +0300
commit012f0a336c84b22c3e20716e4820f3342afef5d3 (patch)
tree00170e02918c2ae92c1c9a3b6e6145c01f954a15 /source
parent206021113da61f352d96805af7e82e9d41dd70b9 (diff)
=== PyNodes ===
* Make PyNodes work with threaded renderer. This patch is by Willian. He has worked hard on getting this sorted out - now you should be able to render with PyNodes AND multiple threads.
Diffstat (limited to 'source')
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c176
-rw-r--r--source/blender/python/BPY_interface.c198
-rw-r--r--source/blender/python/api2_2x/Draw.c16
-rw-r--r--source/blender/python/api2_2x/Window.c6
-rw-r--r--source/blender/src/drawnode.c5
-rw-r--r--source/blender/src/space.c19
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp14
7 files changed, 367 insertions, 67 deletions
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
index 1d1cf3d7e23..ec3a9f3e5d6 100644
--- a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
@@ -43,11 +43,19 @@
static void node_dynamic_setup(bNode *node);
static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
+static void node_dynamic_free_storage_cb(bNode *node);
static PyObject *init_dynamicdict(void) {
- PyObject *newscriptdict= PyDict_New();
+ PyObject *newscriptdict;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ newscriptdict= PyDict_New();
+
PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
EXPP_dict_set_item_str(newscriptdict, "__name__", PyString_FromString("__main__"));
+
+ PyGILState_Release(gilstate);
+
return newscriptdict;
}
@@ -228,12 +236,8 @@ static void node_dynamic_rem_all_links(bNodeType *tinfo)
}
/* node_dynamic_reset: clean a pynode, getting rid of all
- * data dynamically created for it.
- * ntree is used only in a special case: for working pynodes
- * that were saved on a .blend but fail for some reason when
- * the file is opened. We need it because pynodes are initialized
- * before G.main. */
-static void node_dynamic_reset(bNode *node, bNodeTree *ntree)
+ * data dynamically created for it. */
+static void node_dynamic_reset(bNode *node, int unlink_text)
{
bNodeType *tinfo, *tinfo_default;
Material *ma;
@@ -244,16 +248,6 @@ static void node_dynamic_reset(bNode *node, bNodeTree *ntree)
node_dynamic_rem_all_links(tinfo);
node_dynamic_free_typeinfo_sockets(tinfo);
- if (!ntree) { node_dynamic_free_sockets(node); }
-
- //wnode_dynamic_update_socket_links(node, ntree);
- node_dynamic_free_storage_cb(node);
-
- /* XXX hardcoded for shaders: */
- if (node->typeinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
-
- node->typeinfo = tinfo_default;
-
/* reset all other XXX shader nodes sharing this typeinfo */
for (ma= G.main->mat.first; ma; ma= ma->id.next) {
if (ma->nodetree) {
@@ -263,45 +257,129 @@ static void node_dynamic_reset(bNode *node, bNodeTree *ntree)
node_dynamic_free_storage_cb(nd);
node_dynamic_free_sockets(nd);
nd->typeinfo = tinfo_default;
+ if (unlink_text) {
+ nd->id = NULL;
+ nd->custom1 = 0;
+ nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
+ BLI_strncpy(nd->name, "Dynamic", 8);
+ }
}
}
}
}
+ /* XXX hardcoded for shaders: */
+ if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
+ node_dynamic_free_typeinfo(tinfo);
+}
+
+/* Special case of the above function: for working pynodes
+ * that were saved on a .blend but fail for some reason when
+ * the file is opened. We need this because pynodes are initialized
+ * before G.main. */
+static void node_dynamic_reset_loaded(bNode *node)
+{
+ bNodeType *tinfo = node->typeinfo;
+
+ node_dynamic_rem_all_links(tinfo);
+ node_dynamic_free_typeinfo_sockets(tinfo);
+ node_dynamic_free_storage_cb(node);
+ /* XXX hardcoded for shaders: */
+ if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
+
node_dynamic_free_typeinfo(tinfo);
+ node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
}
int nodeDynamicUnlinkText(ID *txtid) {
Material *ma;
- int unlinked= 0;
+ bNode *nd;
+ /* find one node that uses this text */
for (ma= G.main->mat.first; ma; ma= ma->id.next) {
if (ma->nodetree) {
- bNode *nd, *nd2 = NULL;
for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) {
- nd->id = NULL;
+ node_dynamic_reset(nd, 1); /* found, reset all */
+ return 1;
+ }
+ }
+ }
+ }
+ return 0; /* no pynodes used this text */
+}
+
+/*
+static void node_dynamic_free_all_typeinfos(ListBase *list)
+{
+ bNodeType *ntype, *ntnext;
+
+ ntype = list->first;
+
+ while (ntype) {
+ ntnext = ntype->next;
+ if (ntype->type == NODE_DYNAMIC && ntype->id) {
+ BLI_remlink(list, ntype);
+ node_dynamic_free_typeinfo_sockets(ntype);
+ node_dynamic_free_typeinfo(ntype);
+ }
+ ntype = ntnext;
+ }
+}
+*/
+/* Unload all pynodes: since the Game Engine restarts Python, we need
+ * to recreate pynodes dicts and objects. First we get rid of them here: */
+/*
+void nodeDynamicUnloadAll(void)
+{
+ Material *ma;
+ bNode *nd;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if (ma->nodetree) {
+ for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
+ if ((nd->type == NODE_DYNAMIC) && nd->id) {
+ node_dynamic_free_storage_cb(nd);
+ nd->typeinfo = NULL;
nd->custom1 = 0;
- nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
- BLI_strncpy(nd->name, "Dynamic", 8);
- nd2 = nd; /* so we have a ptr to one of them */
- unlinked++;
+ nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_LOADED);
}
}
- /* clean uneeded dynamic data from all nodes that shared
- * this text: */
- if (nd2) node_dynamic_reset(nd2, NULL);
}
}
- return unlinked;
+ node_dynamic_free_all_typeinfos(&node_all_shaders);
+
+ PyGILState_Release(gilstate);
+}
+
+void nodeDynamicReloadAll(void)
+{
+ Material *ma;
+ bNode *nd;
+
+ for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if (ma->nodetree) {
+ for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
+ if ((nd->type == NODE_DYNAMIC) && nd->id) {
+ node_dynamic_setup(nd);
+ }
+ }
+ }
+ }
}
+*/
static void node_dynamic_pyerror_print(bNode *node)
{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name);
if (PyErr_Occurred()) { PyErr_Print(); }
else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); }
+
+ PyGILState_Release(gilstate);
}
static int node_dynamic_parse(struct bNode *node)
@@ -316,6 +394,7 @@ static int node_dynamic_parse(struct bNode *node)
char *buf = NULL;
Py_ssize_t pos = 0;
int is_valid_script = 0;
+ PyGILState_STATE gilstate;
if (!node->id || !node->storage)
return 0;
@@ -324,6 +403,9 @@ static int node_dynamic_parse(struct bNode *node)
if (BTST(node->custom1, NODE_DYNAMIC_READY))
return 0;
+ /* for threading */
+ gilstate = PyGILState_Ensure();
+
nsd = (NodeScriptDict *)node->storage;
dict = (PyObject *)(nsd->dict);
@@ -336,6 +418,7 @@ static int node_dynamic_parse(struct bNode *node)
if (!pyresult) {
node_dynamic_disable(node);
node_dynamic_pyerror_print(node);
+ PyGILState_Release(gilstate);
return -1;
}
@@ -365,7 +448,8 @@ static int node_dynamic_parse(struct bNode *node)
node->typeinfo->pydict = dict;
node->typeinfo->pynode = pynode;
node->typeinfo->id = node->id;
- nodeAddSockets(node, node->typeinfo);
+ if (BNTST(node->custom1, NODE_DYNAMIC_LOADED))
+ nodeAddSockets(node, node->typeinfo);
if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
nodeRegisterType(&node_all_shaders, node->typeinfo);
/* nodeRegisterType copied it to a new one, so we
@@ -386,6 +470,8 @@ static int node_dynamic_parse(struct bNode *node)
}
}
+ PyGILState_Release(gilstate);
+
if (!is_valid_script) { /* not a valid pynode script */
node_dynamic_disable(node);
node_dynamic_pyerror_print(node);
@@ -402,6 +488,7 @@ static void node_dynamic_setup(bNode *node)
NodeScriptDict *nsd = NULL;
bNodeTree *nodetree = NULL;
bNodeType *ntype = NULL;
+ PyGILState_STATE gilstate;
/* Possible cases:
* NEW
@@ -423,9 +510,12 @@ static void node_dynamic_setup(bNode *node)
if (BTST(node->custom1, NODE_DYNAMIC_READY))
return;
+ gilstate = PyGILState_Ensure();
+
/* ERROR, reset to (empty) defaults */
if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
- node_dynamic_reset(node, NULL);
+ node_dynamic_reset(node, 0);
+ PyGILState_Release(gilstate);
return;
}
@@ -459,6 +549,7 @@ static void node_dynamic_setup(bNode *node)
node->storage = nsd;
/* prepared, now reparse: */
node_dynamic_parse(node);
+ PyGILState_Release(gilstate);
return;
}
}
@@ -492,8 +583,9 @@ static void node_dynamic_setup(bNode *node)
nodeMakeDynamicType(node);
nsd->dict = init_dynamicdict();
if ((node_dynamic_parse(node) == -1) && nodetree) {
- node_dynamic_reset(node, nodetree);
+ node_dynamic_reset_loaded(node);
}
+ PyGILState_Release(gilstate);
return;
}
}
@@ -502,6 +594,7 @@ static void node_dynamic_setup(bNode *node)
* we just reuse existing py dict and pynode */
nsd->dict = node->typeinfo->pydict;
nsd->node = node->typeinfo->pynode;
+
Py_INCREF((PyObject *)(nsd->dict));
Py_INCREF((PyObject *)(nsd->node));
@@ -513,6 +606,8 @@ static void node_dynamic_setup(bNode *node)
node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
+ PyGILState_Release(gilstate);
+
return;
}
@@ -546,16 +641,21 @@ static void node_dynamic_init_cb(bNode *node) {
static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
{
NodeScriptDict *nsd;
+ PyGILState_STATE gilstate;
if (!orig_node->storage) return;
nsd = (NodeScriptDict *)(orig_node->storage);
new_node->storage = MEM_dupallocN(orig_node->storage);
+ gilstate = PyGILState_Ensure();
+
if (nsd->node)
Py_INCREF((PyObject *)(nsd->node));
if (nsd->dict)
Py_INCREF((PyObject *)(nsd->dict));
+
+ PyGILState_Release(gilstate);
}
/* node_dynamic_exec_cb: the execution callback called per pixel
@@ -566,12 +666,13 @@ static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNode
PyObject *pyresult = NULL;
PyObject *args = NULL;
ShadeInput *shi;
+ PyGILState_STATE gilstate;
if (!node->id)
return;
- if (G.scene->r.threads > 1)
- return;
+ /*if (G.scene->r.threads > 1)
+ return;*/
if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
node_dynamic_setup(node);
@@ -585,9 +686,13 @@ static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNode
if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
nsd = (NodeScriptDict *)node->storage;
-
mynode = (BPy_Node *)(nsd->node);
+
+
if (mynode && PyCallable_Check((PyObject *)mynode)) {
+
+ gilstate = PyGILState_Ensure();
+
mynode->node = node;
shi = ((ShaderCallData *)data)->shi;
@@ -600,12 +705,14 @@ static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNode
Py_DECREF(args);
if (!pyresult) {
+ PyGILState_Release(gilstate);
node_dynamic_disable_all_by_id(node->id);
node_dynamic_pyerror_print(node);
node_dynamic_setup(node);
return;
}
Py_DECREF(pyresult);
+ PyGILState_Release(gilstate);
}
}
}
@@ -627,3 +734,4 @@ bNodeType node_dynamic_typeinfo = {
/* id */ NULL
};
+
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
index 9d28e8f9e38..b1fd48d87e6 100644
--- a/source/blender/python/BPY_interface.c
+++ b/source/blender/python/BPY_interface.c
@@ -182,6 +182,7 @@ PyObject *traceback_getFilename( PyObject * tb );
****************************************************************************/
void BPY_start_python( int argc, char **argv )
{
+ PyThreadState *py_tstate = NULL;
static int argc_copy = 0;
static char **argv_copy = NULL;
int first_time = argc;
@@ -227,6 +228,9 @@ void BPY_start_python( int argc, char **argv )
Py_Initialize( );
PySys_SetArgv( argc_copy, argv_copy );
+ /* Initialize thread support (also acquires lock) */
+ PyEval_InitThreads();
+
//Overrides __import__
init_ourImport( );
init_ourReload( );
@@ -237,6 +241,10 @@ void BPY_start_python( int argc, char **argv )
//Look for a python installation
init_syspath( first_time ); /* not first_time: some msgs are suppressed */
+ //PyEval_ReleaseLock();
+ py_tstate = PyGILState_GetThisThreadState();
+ PyEval_ReleaseThread(py_tstate);
+
return;
}
@@ -247,6 +255,8 @@ void BPY_end_python( void )
{
Script *script = NULL;
+ PyGILState_Ensure(); /* finalizing, no need to grab the state */
+
if( bpy_registryDict ) {
Py_DECREF( bpy_registryDict );
bpy_registryDict = NULL;
@@ -392,7 +402,6 @@ void init_syspath( int first_time )
}
}
-
void BPY_rebuild_syspath( void )
{
PyObject *mod, *dict, *syspath;
@@ -444,6 +453,7 @@ void BPY_rebuild_syspath( void )
}
Py_DECREF(mod);
+
}
/****************************************************************************
@@ -457,8 +467,12 @@ that dir info is available.
****************************************************************************/
void BPY_post_start_python( void )
{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
BPY_rebuild_syspath();
BPyMenu_Init( 0 ); /* get dynamic menus (registered scripts) data */
+
+ PyGILState_Release(gilstate);
}
/****************************************************************************
@@ -599,6 +613,7 @@ int BPY_txt_do_python_Text( struct Text *text )
BPy_constant *info;
char textname[24];
Script *script = G.main->script.first;
+ PyGILState_STATE gilstate;
if( !text )
return 0;
@@ -639,10 +654,13 @@ int BPY_txt_do_python_Text( struct Text *text )
script->py_button = NULL;
script->py_browsercallback = NULL;
+ gilstate = PyGILState_Ensure();
+
py_dict = CreateGlobalDictionary( );
if( !setup_armature_weakrefs()){
printf("Oops - weakref dict\n");
+ PyGILState_Release(gilstate);
return 0;
}
@@ -667,7 +685,7 @@ int BPY_txt_do_python_Text( struct Text *text )
script->py_globaldict = NULL;
if( G.main->script.first )
free_libblock( &G.main->script, script );
-
+ PyGILState_Release(gilstate);
return 0;
} else {
Py_DECREF( py_result );
@@ -679,6 +697,8 @@ int BPY_txt_do_python_Text( struct Text *text )
}
}
+ PyGILState_Release(gilstate);
+
return 1; /* normal return */
}
@@ -759,12 +779,15 @@ int BPY_menu_do_python( short menutype, int event )
char scriptname[21];
Script *script = NULL;
int len;
+ PyGILState_STATE gilstate;
pym = BPyMenu_GetEntry( menutype, ( short ) event );
if( !pym )
return 0;
+ gilstate = PyGILState_Ensure();
+
if( pym->version > G.version )
notice( "Version mismatch: script was written for Blender %d. "
"It may fail with yours: %d.", pym->version,
@@ -787,8 +810,10 @@ int BPY_menu_do_python( short menutype, int event )
while( arg-- )
pysm = pysm->next;
pyarg = PyString_FromString( pysm->arg );
- } else
+ } else {
+ PyGILState_Release(gilstate);
return 0;
+ }
}
}
@@ -810,6 +835,7 @@ int BPY_menu_do_python( short menutype, int event )
if (!scriptsdir) {
printf("Error loading script: can't find default scripts dir!");
+ PyGILState_Release(gilstate);
return 0;
}
@@ -820,6 +846,7 @@ int BPY_menu_do_python( short menutype, int event )
if( !fp ) {
printf( "Error loading script: couldn't open file %s\n",
filestr );
+ PyGILState_Release(gilstate);
return 0;
}
@@ -838,6 +865,7 @@ int BPY_menu_do_python( short menutype, int event )
if( !script ) {
printf( "couldn't allocate memory for Script struct!" );
fclose( fp );
+ PyGILState_Release(gilstate);
return 0;
}
@@ -944,6 +972,7 @@ int BPY_menu_do_python( short menutype, int event )
if( !setup_armature_weakrefs()){
printf("Oops - weakref dict\n");
MEM_freeN( buffer );
+ PyGILState_Release(gilstate);
return 0;
}
@@ -962,6 +991,7 @@ int BPY_menu_do_python( short menutype, int event )
free_libblock( &G.main->script, script );
error( "Python script error: check console" );
+ PyGILState_Release(gilstate);
return 0;
} else {
Py_DECREF( py_res );
@@ -983,6 +1013,8 @@ int BPY_menu_do_python( short menutype, int event )
}
}
+ PyGILState_Release(gilstate);
+
return 1; /* normal return */
}
@@ -1005,14 +1037,20 @@ void BPY_free_compiled_text( struct Text *text )
*****************************************************************************/
void BPY_free_finished_script( Script * script )
{
+ PyGILState_STATE gilstate;
+
if( !script )
return;
+ gilstate = PyGILState_Ensure();
+
if( PyErr_Occurred( ) ) { /* if script ended after filesel */
PyErr_Print( ); /* eventual errors are handled now */
error( "Python script error: check console" );
}
+ PyGILState_Release(gilstate);
+
free_libblock( &G.main->script, script );
return;
}
@@ -1047,13 +1085,17 @@ static void unlink_script( Script * script )
void BPY_clear_script( Script * script )
{
PyObject *dict;
+ PyGILState_STATE gilstate;
if( !script )
return;
+ gilstate = PyGILState_Ensure();
+
if (!Py_IsInitialized()) {
printf("\nError: trying to free script data after finalizing Python!");
printf("\nScript name: %s\n", script->id.name+2);
+ PyGILState_Release(gilstate);
return;
}
@@ -1074,6 +1116,8 @@ void BPY_clear_script( Script * script )
script->py_globaldict = NULL;
}
+ PyGILState_Release(gilstate);
+
unlink_script( script );
}
@@ -1229,11 +1273,14 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
/* script does exist. it is assumed that this is a valid pyconstraint script */
PyObject *globals;
PyObject *retval, *gval;
+ PyGILState_STATE gilstate;
int num, i;
/* clear the relevant flags first */
data->flag = 0;
-
+
+ gilstate = PyGILState_Ensure();
+
/* populate globals dictionary */
globals = CreateGlobalDictionary();
retval = RunPython(data->text, globals);
@@ -1242,6 +1289,7 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
BPY_Err_Handle(data->text->id.name);
ReleaseGlobalDictionary(globals);
data->flag |= PYCON_SCRIPTERROR;
+ PyGILState_Release(gilstate);
return;
}
@@ -1297,6 +1345,10 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
/* clear globals */
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
+
+ return;
}
else {
/* NUM_TARGETS is not defined or equals 0 */
@@ -1307,6 +1359,8 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
data->tarnum = 0;
data->flag &= ~PYCON_USETARGETS;
+ PyGILState_Release(gilstate);
+
return;
}
}
@@ -1335,10 +1389,13 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
bConstraintTarget *ct;
MatrixObject *retmat;
int row, col, index;
-
+ PyGILState_STATE gilstate;
+
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
-
+
+ gilstate = PyGILState_Ensure();
+
globals = CreateGlobalDictionary();
/* wrap blender-data as PyObjects for evaluation
@@ -1357,6 +1414,8 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
if (!setup_armature_weakrefs()) {
fprintf(stderr, "Oops - weakref dict setup\n");
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1372,7 +1431,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1389,7 +1450,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1408,7 +1471,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1422,7 +1487,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(tarmats);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1437,7 +1504,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1452,7 +1521,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1471,6 +1542,8 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
/* clear globals */
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
}
/* This evaluates the target matrix for each target the PyConstraint uses.
@@ -1485,11 +1558,14 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
PyObject *pyargs, *retval;
MatrixObject *retmat;
int row, col;
-
+ PyGILState_STATE gilstate;
+
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
if (!ct) return;
+ gilstate = PyGILState_Ensure();
+
globals = CreateGlobalDictionary();
tar = Object_CreatePyObject(ct->tar);
@@ -1506,6 +1582,7 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
if (!setup_armature_weakrefs()) {
fprintf(stderr, "Oops - weakref dict setup\n");
+ PyGILState_Release(gilstate);
return;
}
@@ -1522,7 +1599,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1539,7 +1618,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
-
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1559,6 +1640,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1574,6 +1658,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(tarmat);
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1587,6 +1674,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1602,6 +1692,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
Py_XDECREF(retval);
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1621,6 +1714,8 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
/* clear globals */
ReleaseGlobalDictionary(globals);
+
+ PyGILState_Release(gilstate);
}
/* This draws+handles the user-defined interface for editing pyconstraints idprops */
@@ -1631,6 +1726,7 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
PyObject *globals;
PyObject *gval;
PyObject *retval;
+ PyGILState_STATE gilstate;
if (!con->text) return;
if (con->flag & PYCON_SCRIPTERROR) return;
@@ -1648,6 +1744,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
/* free temp objects */
Py_XDECREF(idprop);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1661,6 +1760,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
/* free temp objects */
ReleaseGlobalDictionary( globals );
Py_XDECREF(idprop);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1673,6 +1775,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
ReleaseGlobalDictionary( globals );
Py_XDECREF(idprop);
+
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1683,6 +1788,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
/* free temp objects */
ReleaseGlobalDictionary(globals);
Py_XDECREF(idprop);
+
+ PyGILState_Release(gilstate);
+
return;
}
else {
@@ -1692,6 +1800,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
/* free temp objects */
Py_XDECREF(idprop);
Py_DECREF(retval);
+
+ PyGILState_Release(gilstate);
+
return;
}
}
@@ -1702,12 +1813,16 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
* updates in it reach pydriver evaluation. */
void BPY_pydriver_update(void)
{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
PyDict_Clear(bpy_pydriver_Dict);
Py_DECREF(bpy_pydriver_Dict);
bpy_pydriver_Dict = NULL;
}
+ PyGILState_Release(gilstate);
+
return;
}
@@ -1750,15 +1865,19 @@ float BPY_pydriver_eval(IpoDriver *driver)
PyObject *retval, *bpy_ob = NULL;
float result = 0.0f; /* default return */
int setitem_retval;
+ PyGILState_STATE gilstate;
if (!driver) return result;
expr = driver->name; /* the py expression to be evaluated */
if (!expr || expr[0]=='\0') return result;
+ gilstate = PyGILState_Ensure();
+
if (!bpy_pydriver_Dict) {
if (bpy_pydriver_create_dict() != 0) {
fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
+ PyGILState_Release(gilstate);
return result;
}
}
@@ -1775,6 +1894,7 @@ float BPY_pydriver_eval(IpoDriver *driver)
if( !setup_armature_weakrefs()){
fprintf( stderr, "Oops - weakref dict setup\n");
+ PyGILState_Release(gilstate);
return result;
}
@@ -1782,13 +1902,18 @@ float BPY_pydriver_eval(IpoDriver *driver)
bpy_pydriver_Dict);
if (retval == NULL) {
- return pydriver_error(driver);
+ result = pydriver_error(driver);
+ PyGILState_Release(gilstate);
+ return result;
}
result = ( float )PyFloat_AsDouble( retval );
- if (result == -1 && PyErr_Occurred())
- return pydriver_error(driver);
+ if (result == -1 && PyErr_Occurred()) {
+ result = pydriver_error(driver);
+ PyGILState_Release(gilstate);
+ return result;
+ }
/* remove 'self', since this dict is also used by py buttons */
if (setitem_retval == 0) PyDict_DelItemString(bpy_pydriver_Dict, "self");
@@ -1796,6 +1921,8 @@ float BPY_pydriver_eval(IpoDriver *driver)
/* all fine, make sure the "invalid expression" flag is cleared */
driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+ PyGILState_Release(gilstate);
+
return result;
}
@@ -1832,15 +1959,20 @@ static int bpy_button_eval_error(char *expr) {
int BPY_button_eval(char *expr, double *value)
{
PyObject *retval, *floatval;
+ PyGILState_STATE gilstate;
+ int ret;
if (!value || !expr || expr[0]=='\0') return -1;
*value = 0.0; /* default value */
+ gilstate = PyGILState_Ensure();
+
if (!bpy_pydriver_Dict) {
if (bpy_pydriver_create_dict() != 0) {
fprintf(stderr,
"Button Python Eval error: couldn't create Python dictionary");
+ PyGILState_Release(gilstate);
return -1;
}
}
@@ -1848,6 +1980,7 @@ int BPY_button_eval(char *expr, double *value)
if( !setup_armature_weakrefs()){
fprintf(stderr, "Oops - weakref dict\n");
+ PyGILState_Release(gilstate);
return -1;
}
@@ -1855,20 +1988,26 @@ int BPY_button_eval(char *expr, double *value)
bpy_pydriver_Dict);
if (retval == NULL) {
- return bpy_button_eval_error(expr);
+ ret = bpy_button_eval_error(expr);
+ PyGILState_Release(gilstate);
+ return ret;
}
else {
floatval = PyNumber_Float(retval);
Py_DECREF(retval);
}
- if (floatval == NULL)
- return bpy_button_eval_error(expr);
- else {
+ if (floatval == NULL) {
+ ret = bpy_button_eval_error(expr);
+ PyGILState_Release(gilstate);
+ return ret;
+ } else {
*value = (float)PyFloat_AsDouble(floatval);
Py_DECREF(floatval);
}
+ PyGILState_Release(gilstate);
+
return 0; /* successful exit */
}
@@ -1973,19 +2112,24 @@ void BPY_do_pyscript( ID * id, short event )
PyObject *dict;
PyObject *ret;
int index, during_slink = during_scriptlink( );
+ PyGILState_STATE gilstate;
/* invalid scriptlinks (new .blend was just loaded), return */
if( during_slink < 0 )
return;
-
+
+ gilstate = PyGILState_Ensure();
+
if( !setup_armature_weakrefs()){
printf("Oops - weakref dict, this is a bug\n");
+ PyGILState_Release(gilstate);
return;
}
value = GetPyObjectFromID( id );
if( !value){
printf("Oops - could not get a valid python object for Blender.link, this is a bug\n");
+ PyGILState_Release(gilstate);
return;
}
@@ -2039,6 +2183,8 @@ void BPY_do_pyscript( ID * id, short event )
PyDict_SetItemString(g_blenderdict, "bylink", Py_False);
PyDict_SetItemString( g_blenderdict, "link", Py_None );
EXPP_dict_set_item_str( g_blenderdict, "event", PyString_FromString( "" ) );
+
+ PyGILState_Release(gilstate);
}
}
@@ -2190,6 +2336,7 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
{
ScriptLink *scriptlink;
int retval = 0;
+ PyGILState_STATE gilstate;
if (!sa || !(G.f & G_DOSCRIPTLINKS)) return 0;
@@ -2213,8 +2360,11 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
disable_where_scriptlink( (short)during_slink );
}
+ gilstate = PyGILState_Ensure();
+
if( !setup_armature_weakrefs()){
printf("Oops - weakref dict, this is a bug\n");
+ PyGILState_Release(gilstate);
return 0;
}
@@ -2290,6 +2440,8 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
* space_event is of type DRAW:
* 0 always */
+ PyGILState_Release(gilstate);
+
return retval;
}
diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c
index fc84c9a1445..da8a87ad218 100644
--- a/source/blender/python/api2_2x/Draw.c
+++ b/source/blender/python/api2_2x/Draw.c
@@ -672,6 +672,7 @@ void BPY_spacescript_do_pywin_draw( SpaceScript * sc )
uiBlock *block;
char butblock[20];
Script *script = sc->script;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
sprintf( butblock, "win %d", curarea->win );
block = uiNewBlock( &curarea->uiblocks, butblock, UI_EMBOSSX,
@@ -696,6 +697,8 @@ void BPY_spacescript_do_pywin_draw( SpaceScript * sc )
uiDrawBlock( block );
curarea->win_swap = WIN_BACK_OK;
+
+ PyGILState_Release(gilstate);
}
static void spacescript_do_pywin_buttons( SpaceScript * sc,
@@ -709,6 +712,8 @@ static void spacescript_do_pywin_buttons( SpaceScript * sc,
void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event,
short val, char ascii )
{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
if( event == QKEY && G.qual & ( LR_ALTKEY | LR_CTRLKEY ) ) {
/* finish script: user pressed ALT+Q or CONTROL+Q */
Script *script = sc->script;
@@ -717,6 +722,8 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event,
script->flags &= ~SCRIPT_GUI; /* we're done with this script */
+ PyGILState_Release(gilstate);
+
return;
}
@@ -729,6 +736,9 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event,
* read the comment before check_button_event() below to understand */
if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000)
spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET);
+
+ PyGILState_Release(gilstate);
+
return;
}
}
@@ -749,6 +759,8 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event,
EXPP_dict_set_item_str(g_blenderdict, "event",
PyString_FromString(""));
}
+
+ PyGILState_Release(gilstate);
}
static void exec_but_callback(void *pyobj, void *data)
@@ -869,9 +881,13 @@ void BPy_Free_DrawButtonsList(void)
{
/*Clear the list.*/
if (M_Button_List) {
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
PyList_SetSlice(M_Button_List, 0, PyList_Size(M_Button_List), NULL);
Py_DECREF(M_Button_List);
M_Button_List = NULL;
+
+ PyGILState_Release(gilstate);
}
}
diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c
index 73edcb2df9c..7d346ed9cd9 100644
--- a/source/blender/python/api2_2x/Window.c
+++ b/source/blender/python/api2_2x/Window.c
@@ -1,5 +1,5 @@
/*
- * $Id: Window.c 12813 2007-12-07 09:51:02Z campbellbarton $
+ * $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@@ -512,6 +512,8 @@ static void getSelectedFile( char *name )
pycallback = script->py_browsercallback;
if (pycallback) {
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
result = PyObject_CallFunction( pycallback, "s", name );
if (!result) {
@@ -525,6 +527,8 @@ static void getSelectedFile( char *name )
/* else another call to selector was made inside pycallback */
Py_DECREF(pycallback);
+
+ PyGILState_Release(gilstate);
}
return;
diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c
index 54475eb362e..d85e3199fb3 100644
--- a/source/blender/src/drawnode.c
+++ b/source/blender/src/drawnode.c
@@ -798,11 +798,6 @@ static int node_shader_buts_dynamic(uiBlock *block, bNodeTree *ntree, bNode *nod
ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect);
snode_drawstring(snode, "Error! Check console...", butr->xmax - butr->xmin);
}
- else if (G.scene->r.threads > 1) {
- BIF_ThemeColor(TH_REDALERT);
- ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect);
- snode_drawstring(snode, "Set threads to 1", butr->xmax - butr->xmin);
- }
}
}
return 20+19;
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 55faa4650df..1994a2fcb7f 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -544,9 +544,14 @@ void start_game(void)
RestoreState();
/* Restart BPY - unload the game engine modules. */
+
+ /* Commented out: testing before Blender 2.46 if it's ok to keep
+ * these modules around, they give access to relevant info for
+ * exporters to other engines...
BPY_end_python();
- BPY_start_python(0, NULL); /* argc, argv stored there already */
- BPY_post_start_python(); /* userpref path and menus init */
+ BPY_start_python(0, NULL);
+ BPY_post_start_python();
+ */
restore_all_scene_cfra(scene_cfra_store);
set_scene_bg(startscene);
@@ -615,10 +620,16 @@ void start_RBSimulation(void)
SaveState();
StartKetsjiShellSimulation(curarea, startscene->id.name+2, G.main,G.sipo, 1);
RestoreState();
+
/* Restart BPY - unload the game engine modules. */
+
+ /* Commented out: testing before Blender 2.46 if it's ok to keep
+ * these modules around, they give access to relevant info for
+ * exporters to other engines...
BPY_end_python();
- BPY_start_python(0, NULL); /* argc, argv stored there already */
- BPY_post_start_python(); /* userpref path and menus init */
+ BPY_start_python(0, NULL);
+ BPY_post_start_python();
+ */
restore_all_scene_cfra(scene_cfra_store);
set_scene_bg(startscene);
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index e89c78614cc..e412fcdf748 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -135,6 +135,10 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
STR_String exitstring = "";
BlendFileData *bfd= NULL;
+ // Acquire Python's GIL (global interpreter lock)
+ // so we can safely run Python code and API calls
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
bgl::InitExtensions(1);
do
@@ -464,6 +468,9 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
} while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
if (bfd) BLO_blendfiledata_free(bfd);
+
+ // Release Python's GIL
+ PyGILState_Release(gilstate);
}
extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
@@ -482,6 +489,10 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
STR_String exitstring = "";
BlendFileData *bfd= NULL;
+ // Acquire Python's GIL (global interpreter lock)
+ // so we can safely run Python code and API calls
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
bgl::InitExtensions(1);
do
@@ -669,4 +680,7 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
} while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
if (bfd) BLO_blendfiledata_free(bfd);
+
+ // Release Python's GIL
+ PyGILState_Release(gilstate);
}