Revision: 46864 http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=46864 Author: moguri Date: 2012-05-22 05:18:53 +0000 (Tue, 22 May 2012) Log Message: ----------- Adding the start to an async option for bge.logic.LibLoad(). The basic threading works, but there are still some issues that need to be addressed: * Memory leaks when canceling a thread. I'll try to fix these with more cleanup callbacks like the one used in async_convert(). * The user has no way of knowing when an asset has been loaded. I'm thinking some sort of Future object would work here. * Only works for scenes. It will be simple to support Mesh and Action as well, but I want to do it in a such a way as to minimize code duplication.
Modified Paths: -------------- branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.cpp branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.h branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_ISceneConverter.h branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_KetsjiEngine.cpp branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_PythonInit.cpp Modified: branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.cpp =================================================================== --- branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.cpp 2012-05-22 02:24:27 UTC (rev 46863) +++ branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.cpp 2012-05-22 05:18:53 UTC (rev 46864) @@ -112,6 +112,13 @@ #include "../../blender/blenlib/BLI_linklist.h" } +#include <pthread.h> + +/* This is used to avoid including pthread.h in KX_BlenderSceneConverter.h */ +typedef struct ThreadInfo { + vector<pthread_t> threads; +} ThreadInfo; + KX_BlenderSceneConverter::KX_BlenderSceneConverter( struct Main* maggie, class KX_KetsjiEngine* engine @@ -125,6 +132,7 @@ { tag_main(maggie, 0); /* avoid re-tagging later on */ m_newfilename = ""; + m_threadinfo = new ThreadInfo(); } @@ -134,6 +142,12 @@ int i; // delete sumoshapes + vector<pthread_t>::iterator pit = m_threadinfo->threads.begin(); + while (pit != m_threadinfo->threads.end()) { + pthread_cancel((*pit)); + pthread_join((*pit), NULL); + pit++; + } int numAdtLists = m_map_blender_to_gameAdtList.size(); for (i=0; i<numAdtLists; i++) { @@ -913,6 +927,67 @@ return NULL; } +void KX_BlenderSceneConverter::MergeAsyncLoads() +{ + vector<pair<KX_Scene*,KX_Scene*> >::iterator sit; + for (sit=m_mergequeue.begin(); sit!=m_mergequeue.end(); ++sit) + { + printf("Merging scene: %s\n", (*sit).first->GetName().ReadPtr()); + (*sit).first->MergeScene((*sit).second); + delete (*sit).second; + } + + m_mergequeue.clear(); +} + +void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_Scene *merge_scene, KX_Scene *other) +{ + m_mergequeue.push_back(pair<KX_Scene*,KX_Scene*>(merge_scene, other)); +} + +typedef struct {KX_BlenderSceneConverter *converter; KX_Scene **scene; struct Main *maggie;} cleanup_args; +void async_cleanup(void *ptr) +{ + cleanup_args *args = (cleanup_args*)ptr; + KX_Scene **scene = args->scene; + if (*scene) + { + delete *scene; + *scene = NULL; + } + + args->converter->FreeBlendFile(args->maggie); + + delete args; + printf("Cleanup called\n"); +} + +typedef struct {KX_BlenderSceneConverter *converter; KX_KetsjiEngine *engine; Scene *scene; struct Main *maggie; KX_Scene *merge_scene;} async_args; +void *async_convert(void *ptr) +{ + int cleanedup=0; + KX_Scene *new_scene=NULL; + async_args *args = (async_args*)ptr; + + cleanup_args *cargs = new cleanup_args(); + cargs->converter = args->converter; + cargs->scene = &new_scene; + cargs->maggie = args->maggie; + + pthread_cleanup_push(async_cleanup, cargs); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + new_scene = args->engine->CreateScene(args->scene); + + pthread_cleanup_pop(cleanedup); + + if (new_scene) + args->converter->AddScenesToMergeQueue(args->merge_scene, new_scene); + + delete args; + delete cargs; + return NULL; +} + bool KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) { BlendHandle *bpy_openlib = BLO_blendhandle_from_memory(data, length); @@ -1037,12 +1112,27 @@ if (options & LIB_LOAD_VERBOSE) printf("SceneName: %s\n", scene->name+2); - /* merge into the base scene */ - KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene); - scene_merge->MergeScene(other); + if (options & LIB_LOAD_ASYNC) + { + pthread_t id; + async_args *args = new async_args(); // Gets deleted in the thread + args->converter = this; + args->engine = m_ketsjiEngine; + args->scene = (Scene*)scene; + args->maggie = main_newlib; + args->merge_scene = scene_merge; + pthread_create(&id, NULL, &async_convert, (void*)args); + m_threadinfo->threads.push_back(id); + } + else + { + /* merge into the base scene */ + KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene); + scene_merge->MergeScene(other); - // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene - delete other; + // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene + delete other; + } } /* Now handle all the actions */ Modified: branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.h =================================================================== --- branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.h 2012-05-22 02:24:27 UTC (rev 46863) +++ branches/soc-2012-swiss_cheese/source/gameengine/Converter/KX_BlenderSceneConverter.h 2012-05-22 05:18:53 UTC (rev 46864) @@ -50,6 +50,7 @@ class BL_Material; struct Main; struct Scene; +struct ThreadInfo; class KX_BlenderSceneConverter : public KX_ISceneConverter { @@ -58,6 +59,10 @@ vector<pair<KX_Scene*,RAS_IPolyMaterial*> > m_polymaterials; vector<pair<KX_Scene*,RAS_MeshObject*> > m_meshobjects; vector<pair<KX_Scene*,BL_Material *> > m_materials; + + vector<pair<KX_Scene*,KX_Scene*> > m_mergequeue; + ThreadInfo *m_threadinfo; + // Should also have a list of collision shapes. // For the time being this is held in KX_Scene::m_shapes @@ -154,6 +159,9 @@ RAS_MeshObject *ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name); bool FreeBlendFile(struct Main *maggie); bool FreeBlendFile(const char *path); + + virtual void MergeAsyncLoads(); + void AddScenesToMergeQueue(KX_Scene *merge_scene, KX_Scene *other); void PrintStats() { printf("BGE STATS!\n"); @@ -182,6 +190,7 @@ { LIB_LOAD_LOAD_ACTIONS = 1, LIB_LOAD_VERBOSE = 2, + LIB_LOAD_ASYNC = 3, }; Modified: branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_ISceneConverter.h =================================================================== --- branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_ISceneConverter.h 2012-05-22 02:24:27 UTC (rev 46863) +++ branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_ISceneConverter.h 2012-05-22 05:18:53 UTC (rev 46864) @@ -61,6 +61,9 @@ virtual void RemoveScene(class KX_Scene *scene)=0; + // handle any pending merges from asynchronous loads + virtual void MergeAsyncLoads()=0; + virtual void SetAlwaysUseExpandFraming(bool to_what) = 0; virtual void SetNewFileName(const STR_String& filename) = 0; Modified: branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_KetsjiEngine.cpp =================================================================== --- branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_KetsjiEngine.cpp 2012-05-22 02:24:27 UTC (rev 46863) +++ branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_KetsjiEngine.cpp 2012-05-22 05:18:53 UTC (rev 46864) @@ -596,6 +596,8 @@ m_frameTime += framestep; + m_sceneconverter->MergeAsyncLoads(); + for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) // for each scene, call the proceed functions { Modified: branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_PythonInit.cpp =================================================================== --- branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_PythonInit.cpp 2012-05-22 02:24:27 UTC (rev 46863) +++ branches/soc-2012-swiss_cheese/source/gameengine/Ketsji/KX_PythonInit.cpp 2012-05-22 05:18:53 UTC (rev 46864) @@ -676,12 +676,12 @@ char *err_str= NULL; short options=0; - int load_actions=0, verbose=0; + int load_actions=0, verbose=0, async=0; - static const char *kwlist[] = {"path", "group", "buffer", "load_actions", "verbose", NULL}; + static const char *kwlist[] = {"path", "group", "buffer", "load_actions", "verbose", "async", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|y*ii:LibLoad", const_cast<char**>(kwlist), - &path, &group, &py_buffer, &load_actions, &verbose)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|y*iii:LibLoad", const_cast<char**>(kwlist), + &path, &group, &py_buffer, &load_actions, &verbose, &async)) return NULL; /* setup options */ @@ -689,7 +689,10 @@ options |= KX_BlenderSceneConverter::LIB_LOAD_LOAD_ACTIONS; if (verbose != 0) options |= KX_BlenderSceneConverter::LIB_LOAD_VERBOSE; + if (async != 0) + options |= KX_BlenderSceneConverter::LIB_LOAD_ASYNC; + if (!py_buffer.buf) { char abs_path[FILE_MAX]; _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs