diff options
author | Nathan Letwory <nathan@letworyinteractive.com> | 2008-02-23 15:05:28 +0300 |
---|---|---|
committer | Nathan Letwory <nathan@letworyinteractive.com> | 2008-02-23 15:05:28 +0300 |
commit | 012f0a336c84b22c3e20716e4820f3342afef5d3 (patch) | |
tree | 00170e02918c2ae92c1c9a3b6e6145c01f954a15 /source | |
parent | 206021113da61f352d96805af7e82e9d41dd70b9 (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.c | 176 | ||||
-rw-r--r-- | source/blender/python/BPY_interface.c | 198 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Draw.c | 16 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Window.c | 6 | ||||
-rw-r--r-- | source/blender/src/drawnode.c | 5 | ||||
-rw-r--r-- | source/blender/src/space.c | 19 | ||||
-rw-r--r-- | source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp | 14 |
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); } |