diff --git a/Docs/src/tutorials/numpy.md b/Docs/src/tutorials/numpy.md index 0d87e618992..fda97c5431a 100644 --- a/Docs/src/tutorials/numpy.md +++ b/Docs/src/tutorials/numpy.md @@ -42,4 +42,23 @@ Now we can store the image to disk using pyplot. @note There is also Ogre::RenderTarget::writeContentsToFile if you do not need the pixel data in Python. -![](numpy_final.png) \ No newline at end of file +![](numpy_final.png) + +## Background Threads {#python-background-threads} + +By default, the Python bindings do not release the GIL (Global Interpreter Lock) during rendering, which means that no other Python code can run in parallel. +This is usually not a problem and constantly re-acquiring the GIL would reduce performance. However, this means that the following code will not work: + +```py +import threading + +def printer(): + for _ in range(15): + print("Thread") + +threading.Thread(target=printer).start() +root.startRendering() +``` + +The "printer" Thread will be blocked until the rendering is finished. +To allow background threads to run, you can use `root.allowPyThread()`, which will release the GIL during swapping, while rendering is waiting for vsync. \ No newline at end of file diff --git a/OgreMain/include/Ogre.i b/OgreMain/include/Ogre.i index d2825625f23..d7850673f65 100644 --- a/OgreMain/include/Ogre.i +++ b/OgreMain/include/Ogre.i @@ -924,12 +924,38 @@ SHARED_PTR(Mesh); %ignore Ogre::Root::createSceneManager(uint16); %ignore Ogre::Root::createSceneManager(uint16, const String&); %ignore Ogre::Root::getMovableObjectFactoryIterator; +#ifdef SWIGPYTHON +%{ +class ThreadAllowFrameListener : public Ogre::FrameListener { + PyThreadState* _save = 0; +public: + bool frameRenderingQueued(const Ogre::FrameEvent& evt) + { + if(!_save) + _save = PyEval_SaveThread(); + return true; + } + bool frameEnded(const Ogre::FrameEvent& evt) + { + if(_save) { + PyEval_RestoreThread(_save); + _save = 0; + } + return true; + } +}; +%} +%extend Ogre::Root { + void allowPyThread() + { + static ThreadAllowFrameListener listener; + $self->addFrameListener(&listener); + } +} +#endif %include "OgreRoot.h" -// dont wrap: platform specific -// %include "OgreWindowEventUtilities.h" -// %include "OgreTimer.h" // dont wrap: not useful in high level languages -// %include "OgreRadixSort.h" +// %include "OgreTimer.h" // %include "OgreString.h" // %include "OgreStringConverter.h" // %include "OgreProfiler.h"