[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