Page MenuHome

Fixed loading bug in blenderplayer
AbandonedPublic

Authored by Christiaan van Walree (Magnus) on Nov 9 2014, 11:44 PM.

Details

Summary

Fixed a bug that crashes the blenderplayer after switching blendfiles a couple of times in the same run.

The problem?
When I took a look at the blender game engine at some point I noticed that the blenderplayer crashed when calling function Py_Finalize() in KX_PythonInit.cpp. So I went to search the internet for an answer... Why does the blenderplayer crash by calling Py_Finalize()?
The answer can be found on https://docs.python.org/3.4/c-api/init.html.

quote from the official Python API:

"Some memory allocated by extension modules may not be freed. Some extensions may not work properly if their initialization routine is called more than once; this can happen if an application calls Py_Initialize() and Py_Finalize() more than once."

Since the playerplayer calls Py_Initialze() and Py_Finalize() every time you switch between a level/blendfile, this could be a problem.

The solution?
The solution looks simple. Just get rid of Py_Finalize() and we're done. Unfortunately this caused the sound in our game to get distorted after switching to another blendfile/level. Therefore, I added a new method sound_exit_ghost() (instead of sound_exit()) that deletes the current AUD_IDevice stored in a shared_ptr. This is called in the StopGameEngine() function. Then in StartGameEngine() function we simply call sound_init() again.

I hope someone is able to review my code so that this sneaky bug will be gone for good.

Cheers!
Christiaan, intern gameprogrammer @ Blue Label Studio

Diff Detail

Event Timeline

Christiaan van Walree (Magnus) retitled this revision from to Fixed loading bug in blenderplayer.
Christiaan van Walree (Magnus) updated this object.
Christiaan van Walree (Magnus) set the repository for this revision to rB Blender.
Christiaan van Walree (Magnus) changed the edit policy from "All Users" to "Custom Policy".
Christiaan van Walree (Magnus) updated this object.
Mitchell Stokes (moguri) requested changes to this revision.Nov 10 2014, 6:03 PM
Mitchell Stokes (moguri) edited edge metadata.

In general, I'd like to see the weird init/cleanup code around loading blend files fixed up since this also makes it more difficult than necessary to transition Python data between files.However, at some point we do need to call Py_Finalize(). Also are we not still initializing Python when loading a new blend file? I'm pretty sure this patch will introduce memory leaks.

This revision now requires changes to proceed.Nov 10 2014, 6:03 PM

Adding Jörg to review the audio changes.

Thanks for your input.

According to the Python API: Py_Initialize() is a 'no-op' when called for a second time without calling Py_Finalize() first. We don't have to worry about that creating a leak. If it is necessary Py_Finalize() can be called when the blenderplayer ends it's main loop. I am quite new to memory management and I thought the memory used by an application would automatically be released when you exit the application.

Is there any way I can update my diff/patch with Py_Finalize() at the end of the main loop or do I have to submit an entirely new one?

First of all: I don't like this kind of hacks and prefer nice solutions.

So the first approach would be: can we fix the Py_Initialize/Py_Finalize problems? It would probably be smartest to really just call them once, that should be possible to implement for blenderplayer? Shall we include Campbell in the discussion? I guess just not calling Py_Finalize but Py_Initialize multiple times leaves even more memory leaks than calling them multiple times.

The second question would be if we really want to do this Py_Finalize hack, why the sound gets distorted, I'd prefer to find that out as it's way more efficient to fix that bug than to unitialize and reinitialize the whole sound system!

And lastly: even if we do this sound reinitialization hack: why exactly are you adding sound_exit_ghost() and what is the name ghost for? The code does nothing different from sound_exit(), actually worse, you directly call the destructor of the device (something you should never do!) before setting the shared pointers to NULL (this calls the destructor!) and thus calling the destructor twice, which results in a pretty bad bug, that could potentially crash the application horribly.

Adding Campbell. Hopefully he can shine some light on a proper fix, or maybe explain why we think we need to keep restarting Python. I get the feeling there is not a good reason other than no one has bothered fixing it.

@Joerg Mueller (nexyon),
I created the sound_exit_ghost() function, because sound_exit() is used by the embedded player. Since the embedded player aint broken I did not want to change anything there. I named the function 'ghost' to the file name where the main loop of the blenderplayer is.

Next, I have to be honest to tell you that I do not have a great understanding of shared_ptr(). I just kept trying my luck to get the blenderplayer to work. sound_exit_ghost() was the only way I managed to get the sound work normal after loading in a new blendfile in the blenderplayer.

I agree that fixing the re-initialization of Python would be a better solution.

BGE was removed in Blender 2.80 this patch is being closed as a result.