=== PyNodes ===
authorNathan Letwory <nathan@letworyinteractive.com>
Sat, 23 Feb 2008 12:05:28 +0000 (12:05 +0000)
committerNathan Letwory <nathan@letworyinteractive.com>
Sat, 23 Feb 2008 12:05:28 +0000 (12:05 +0000)
* 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.

source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
source/blender/python/BPY_interface.c
source/blender/python/api2_2x/Draw.c
source/blender/python/api2_2x/Window.c
source/blender/src/drawnode.c
source/blender/src/space.c
source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp

index 1d1cf3d7e2300ea4c1706ba99b7cb522833e5667..ec3a9f3e5d62e26de57a4bb16cd9ff1cbb84d0ed 100644 (file)
 
 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
 };
 
+
index 9d28e8f9e38bf761b7e513a6b1ac4ba8c7f33be1..b1fd48d87e6f10e5dac71bfb7bb726e04187f621 100644 (file)
@@ -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;
 }
 
index fc84c9a14454ad0800ac24d5b640b51a4bf04645..da8a87ad2185757214da2bce0b2c77a4c9deef1b 100644 (file)
@@ -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);
        }
 }
 
index 73edcb2df9c7dc2d1ab254b15a89934fcd1968be..7d346ed9cd9942063860389457ce2d9633396e72 100644 (file)
@@ -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;
index 54475eb362e23c31eb8cf8b9a095a8759f5237c9..d85e3199fb3dfa2740d9f496bc40ece04d2d5a7b 100644 (file)
@@ -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; 
index 55faa4650dfbb59095ceb45a03248976b82b7424..1994a2fcb7f9d0c2e5daa28c693c8040f3084e30 100644 (file)
@@ -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);
index e89c78614ccbf4e47d00e1c028f34e7817805555..e412fcdf74873c8f96013d3721de6b999c969435 100644 (file)
@@ -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);
 }