[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [46864] branches/soc-2012-swiss_cheese/ source/gameengine: Adding the start to an async option for bge.logic. LibLoad().
Mitchell Stokes
mogurijin at gmail.com
Tue May 22 07:18:57 CEST 2012
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];
More information about the Bf-blender-cvs
mailing list