BGE: Fix issues with async libload.

This patch fixes:
- the call of LibFree on a unfinished loaded library;
- memory leak created on end of game : the async libraries are loaded but not converted, so not freed with the master scene.

Reviewers: campbellbarton, sybren, youle, hg1, moguri, lordloki

Reviewed By: moguri, lordloki

Differential Revision: https://developer.blender.org/D1571
This commit is contained in:
Porteries Tristan 2015-10-25 19:22:29 +01:00
parent 0d59acccd3
commit 06d2ad0185
7 changed files with 53 additions and 10 deletions

View File

@ -25,6 +25,12 @@ base class --- :class:`PyObjectPlus`
:type: callable
.. attribute:: finished
The current status of the lib load.
:type: boolean
.. attribute:: progress
The current progress of the lib load as a normalized value from 0.0 to 1.0.

View File

@ -138,14 +138,6 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
// clears meshes, and hashmaps from blender to gameengine data
// delete sumoshapes
if (m_threadinfo) {
BLI_task_pool_work_and_wait(m_threadinfo->m_pool);
BLI_task_pool_free(m_threadinfo->m_pool);
BLI_mutex_end(&m_threadinfo->m_mutex);
delete m_threadinfo;
}
int numAdtLists = m_map_blender_to_gameAdtList.size();
for (int i = 0; i < numAdtLists; i++) {
BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i);
@ -188,6 +180,15 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
}
m_DynamicMaggie.clear();
if (m_threadinfo) {
/* Thread infos like mutex must be freed after FreeBlendFile function.
Because it needs to lock the mutex, even if there's no active task when it's
in the scene converter destructor. */
BLI_task_pool_free(m_threadinfo->m_pool);
BLI_mutex_end(&m_threadinfo->m_mutex);
delete m_threadinfo;
}
}
void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename)
@ -806,6 +807,16 @@ void KX_BlenderSceneConverter::MergeAsyncLoads()
BLI_mutex_unlock(&m_threadinfo->m_mutex);
}
void KX_BlenderSceneConverter::FinalizeAsyncLoads()
{
// Finish all loading libraries.
if (m_threadinfo) {
BLI_task_pool_work_and_wait(m_threadinfo->m_pool);
}
// Merge all libraries data in the current scene, to avoid memory leak of unmerged scenes.
MergeAsyncLoads();
}
void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status)
{
BLI_mutex_lock(&m_threadinfo->m_mutex);
@ -1017,7 +1028,19 @@ bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
if (maggie == NULL)
return false;
// If the given library is currently in loading, we do nothing.
if (m_status_map.count(maggie->name)) {
BLI_mutex_lock(&m_threadinfo->m_mutex);
const bool finished = m_status_map[maggie->name]->IsFinished();
BLI_mutex_unlock(&m_threadinfo->m_mutex);
if (!finished) {
printf("Library (%s) is currently being loaded asynchronously, and cannot be freed until this process is done\n", maggie->name);
return false;
}
}
/* tag all false except the one we remove */
for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
Main *main = *it;

View File

@ -184,6 +184,7 @@ public:
bool FreeBlendFile(const char *path);
virtual void MergeAsyncLoads();
virtual void FinalizeAsyncLoads();
void AddScenesToMergeQueue(class KX_LibLoadStatus *status);
void PrintStats() {

View File

@ -36,7 +36,8 @@ KX_LibLoadStatus::KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter,
m_mergescene(merge_scene),
m_data(NULL),
m_libname(path),
m_progress(0.f)
m_progress(0.0f),
m_finished(false)
#ifdef WITH_PYTHON
,
m_finish_cb(NULL),
@ -48,6 +49,7 @@ KX_LibLoadStatus::KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter,
void KX_LibLoadStatus::Finish()
{
m_finished = true;
m_progress = 1.f;
m_endtime = PIL_check_seconds_timer();
@ -157,6 +159,7 @@ PyAttributeDef KX_LibLoadStatus::Attributes[] = {
KX_PYATTRIBUTE_FLOAT_RO("progress", KX_LibLoadStatus, m_progress),
KX_PYATTRIBUTE_STRING_RO("libraryName", KX_LibLoadStatus, m_libname),
KX_PYATTRIBUTE_RO_FUNCTION("timeTaken", KX_LibLoadStatus, pyattr_get_timetaken),
KX_PYATTRIBUTE_BOOL_RO("finished", KX_LibLoadStatus, m_finished),
{ NULL } //Sentinel
};

View File

@ -43,6 +43,9 @@ private:
double m_starttime;
double m_endtime;
// The current status of this libload, used by the scene converter.
bool m_finished;
#ifdef WITH_PYTHON
PyObject* m_finish_cb;
PyObject* m_progress_cb;
@ -68,6 +71,11 @@ public:
void SetData(void *data);
void *GetData();
inline bool IsFinished() const
{
return m_finished;
}
void SetProgress(float progress);
float GetProgress();
void AddProgress(float progress);

View File

@ -64,6 +64,7 @@ public:
// handle any pending merges from asynchronous loads
virtual void MergeAsyncLoads()=0;
virtual void FinalizeAsyncLoads() = 0;
virtual void SetAlwaysUseExpandFraming(bool to_what) = 0;

View File

@ -1273,6 +1273,7 @@ void KX_KetsjiEngine::StopEngine()
{
if (m_bInitialized)
{
m_sceneconverter->FinalizeAsyncLoads();
if (m_animation_record)
{