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

Reply via email to