Răsfoiți Sursa

Load resources in background thread - test -

Daniele Bartolini 13 ani în urmă
părinte
comite
264d612bf3
4 a modificat fișierele cu 107 adăugiri și 87 ștergeri
  1. 44 37
      src/ResourceLoader.cpp
  2. 23 14
      src/ResourceLoader.h
  3. 30 26
      src/ResourceManager.cpp
  4. 10 10
      src/ResourceManager.h

+ 44 - 37
src/ResourceLoader.cpp

@@ -30,6 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Hash.h"
 #include "TextureResource.h"
 #include "TextResource.h"
+#include "Log.h"
 #include <stdio.h>
 #include <unistd.h>
 
@@ -40,9 +41,9 @@ namespace crown
 ResourceLoader::ResourceLoader(Allocator& resource_allocator, ResourceArchive& archive) :
 	m_resource_allocator(resource_allocator),
 	m_resource_archive(archive),
-	m_resources(m_allocator),
-	m_loading_callback(NULL),
-	m_online_callback(NULL)
+	m_waiting_resources(m_allocator),
+	m_loaded_resources(m_allocator),
+	m_thread(ResourceLoader::background_thread, (void*)this, "resource-loader-thread")
 {
 	// FIXME hardcoded seed
 	m_config_hash = hash::murmur2_32("config", string::strlen("config"), 0);
@@ -59,13 +60,11 @@ ResourceLoader::~ResourceLoader()
 //-----------------------------------------------------------------------------
 void ResourceLoader::load(ResourceId name)
 {
-	m_resources.push_back(name);
-	
-	// callback to the resource manager
-	if (m_loading_callback != NULL)
-	{
-		m_loading_callback(name);
-	}
+	m_waiting_mutex.lock();
+
+	m_waiting_resources.push_back(name);
+
+	m_waiting_mutex.unlock();
 }
 
 //-----------------------------------------------------------------------------
@@ -75,49 +74,49 @@ void ResourceLoader::unload(ResourceId name, void* resource)
 }
 
 //-----------------------------------------------------------------------------
-void ResourceLoader::flush()
+void ResourceLoader::background_load()
 {
-	while (m_resources.size() > 0)
+	// FIXME: Maybe epic crash because of concurrent access to the same allocator?
+	while (true)
 	{
-		ResourceId& resource = m_resources.front();
-		
-		void* data = load_by_type(resource);
-
-		if (m_online_callback != NULL)
+		if (m_waiting_resources.size() > 0)
 		{
-			m_online_callback(m_resources.front(), data);
-		}
+			m_waiting_mutex.lock();
 
-		m_resources.pop_front();
-	}
-}
+			ResourceId resource = m_waiting_resources.front();
+			m_waiting_resources.pop_front();
 
-//-----------------------------------------------------------------------------
-void ResourceLoader::set_loading_callback(ResourceLoadingCallback f)
-{
-	m_loading_callback = f;
-}
+			m_waiting_mutex.unlock();
 
-//-----------------------------------------------------------------------------
-void ResourceLoader::set_online_callback(ResourceOnlineCallback f)
-{
-	m_online_callback = f;
+			void* data = load_by_type(resource);
+
+			LoadedResource lr;
+			lr.resource = resource;
+			lr.data = data;
+
+			m_loaded_mutex.lock();
+
+			m_loaded_resources.push_back(lr);
+
+			m_loaded_mutex.unlock();
+			
+			m_waiting_mutex.unlock();
+		}
+	}
 }
 
 //-----------------------------------------------------------------------------
-void* ResourceLoader::load_by_type(ResourceId name)
+void* ResourceLoader::load_by_type(ResourceId name) const
 {
 	if (name.type == m_config_hash)
 	{
 		return NULL;
 	}
-
-	if (name.type == m_texture_hash)
+	else if (name.type == m_texture_hash)
 	{
 		return TextureResource::load(m_resource_allocator, &m_resource_archive, name);
 	}
-
-	if (name.type == m_txt_hash)
+	else if (name.type == m_txt_hash)
 	{
 		return TextResource::load(m_resource_allocator, &m_resource_archive, name);
 	}
@@ -126,7 +125,7 @@ void* ResourceLoader::load_by_type(ResourceId name)
 }
 
 //-----------------------------------------------------------------------------
-void ResourceLoader::unload_by_type(ResourceId name, void* resource)
+void ResourceLoader::unload_by_type(ResourceId name, void* resource) const
 {
 	if (name.type == m_config_hash)
 	{
@@ -146,4 +145,12 @@ void ResourceLoader::unload_by_type(ResourceId name, void* resource)
 	return;
 }
 
+//-----------------------------------------------------------------------------
+void* ResourceLoader::background_thread(void* thiz)
+{
+	ResourceLoader* loader = (ResourceLoader*)thiz;
+
+	loader->background_load();
+}
+
 } // namespace crown

+ 23 - 14
src/ResourceLoader.h

@@ -28,17 +28,22 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Queue.h"
 #include "Resource.h"
 #include "MallocAllocator.h"
+#include "ResourceManager.h"
+#include "OS.h"
+#include "Thread.h"
+#include "Mutex.h"
 
 namespace crown
 {
 
-class ResourceManager;
 class Allocator;
 class ResourceArchive;
 
-// Callbacks typedefs
-typedef void (*ResourceLoadingCallback)(ResourceId);
-typedef void (*ResourceOnlineCallback)(ResourceId, void*);
+struct LoadedResource
+{
+	ResourceId	resource;
+	void*		data;
+};
 
 class ResourceLoader
 {
@@ -50,15 +55,15 @@ public:
 	void				load(ResourceId name);
 	void				unload(ResourceId name, void* resource);
 
-	void				flush();
+private:
 
-	void				set_loading_callback(ResourceLoadingCallback f);
-	void				set_online_callback(ResourceOnlineCallback f);
+	void				background_load();
+	void*				load_by_type(ResourceId name) const;
+	void				unload_by_type(ResourceId name, void* resource) const;
 
 private:
 
-	void*				load_by_type(ResourceId name);
-	void				unload_by_type(ResourceId name, void* resource);
+	static void*		background_thread(void* thiz);
 
 private:
 
@@ -66,16 +71,20 @@ private:
 	ResourceArchive&	m_resource_archive;
 
 	MallocAllocator		m_allocator;
-	Queue<ResourceId>	m_resources;
 
-	// Callbacks
-	ResourceLoadingCallback m_loading_callback;
-	ResourceOnlineCallback	m_online_callback;
-	
+	Mutex				m_waiting_mutex;
+	Queue<ResourceId>	m_waiting_resources;
+	Mutex				m_loaded_mutex;
+	Queue<LoadedResource>	m_loaded_resources;
+
+	Thread				m_thread;
+
 	uint32_t			m_config_hash;
 	uint32_t			m_texture_hash;
 	uint32_t			m_mesh_hash;
 	uint32_t			m_txt_hash;
+
+	friend class		ResourceManager;
 };
 
 } // namespace crown

+ 30 - 26
src/ResourceManager.cpp

@@ -40,7 +40,8 @@ namespace crown
 //-----------------------------------------------------------------------------
 ResourceManager::ResourceManager(ResourceLoader& loader) :
 	m_resource_loader(loader),
-	m_resources(m_allocator)
+	m_resources(m_allocator),
+	m_loading_queue(m_allocator)
 {
 }
 
@@ -75,19 +76,20 @@ ResourceId ResourceManager::load(uint32_t name, uint32_t type)
 	if (entry == m_resources.end())
 	{
 		ResourceId id;
+
 		id.name = name;
 		id.type = type;
 		id.index = m_resources.size();
 
 		ResourceEntry entry;
+
 		entry.id = id;
 		entry.state = RS_UNLOADED;
 		entry.references = 1;
 		entry.resource = NULL;
 
 		m_resources.push_back(entry);
-
-		m_resource_loader.load(id);
+		m_loading_queue.push_back(id);
 
 		return id;
 	}
@@ -165,24 +167,42 @@ uint32_t ResourceManager::references(ResourceId name) const
 }
 
 //-----------------------------------------------------------------------------
-void ResourceManager::flush()
+void ResourceManager::flush_load_queue()
 {
-	m_resource_loader.flush();
+	while (m_loading_queue.size() > 0)
+	{
+		ResourceId resource = m_loading_queue.front();
+
+		m_resource_loader.load(resource);
+
+		m_loading_queue.pop_front();
+
+		m_resources[resource.index].state = RS_LOADING;
+	}
 }
 
 //-----------------------------------------------------------------------------
-void ResourceManager::loading(ResourceId name)
+void ResourceManager::bring_loaded_online()
 {
-	assert(has(name));
+	m_resource_loader.m_loaded_mutex.lock();
 
-	m_resources[name.index].state = RS_LOADING;
+	Queue<LoadedResource>& loaded = m_resource_loader.m_loaded_resources;
+
+	while (loaded.size() > 0)
+	{
+		LoadedResource lr = loaded.front();
+
+		online(lr.resource, lr.data);
+
+		loaded.pop_front();
+	}
+
+	m_resource_loader.m_loaded_mutex.unlock();
 }
 
 //-----------------------------------------------------------------------------
 void ResourceManager::online(ResourceId name, void* resource)
 {
-	assert(has(name));
-
 	ResourceEntry& entry = m_resources[name.index];
 
 	// FIXME hardcoded seed
@@ -195,21 +215,5 @@ void ResourceManager::online(ResourceId name, void* resource)
 	entry.state = RS_LOADED;
 }
 
-//-----------------------------------------------------------------------------
-void ResourceManager::loading_callback_wrapper(void* thiz, ResourceId name)
-{
-	ResourceManager* self = (ResourceManager*)thiz;
-
-	self->loading(name);
-}
-
-//-----------------------------------------------------------------------------
-void ResourceManager::online_callback_wrapper(void* thiz, ResourceId name, void* resource)
-{
-	ResourceManager* self = (ResourceManager*)thiz;
-
-	self->online(name, resource);
-}
-
 } // namespace crown
 

+ 10 - 10
src/ResourceManager.h

@@ -27,6 +27,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "List.h"
+#include "Queue.h"
 #include "Resource.h"
 #include "MallocAllocator.h"
 
@@ -75,8 +76,12 @@ public:
 	/// See ResourceManager::load(const char* name) for details.
 	ResourceId				load(uint32_t name, uint32_t type);
 
+	/// Unloads the @resource, freeing up all the memory associated by it
+	/// and eventually any global object associated with it.
+	/// (Such as texture objects, vertex buffers etc.)
 	void					unload(ResourceId name);
 
+	/// Reloads the @resource
 	void					reload(ResourceId name);
 
 	/// Returns whether the manager has the @name resource into
@@ -97,19 +102,14 @@ public:
 	/// you can use the data associated with it).
 	bool					is_loaded(ResourceId name) const;
 
-	// Returns the number of references of the @name resource
+	// Returns the number of references to the @resource
 	uint32_t				references(ResourceId name) const;
-	
-	/// Forces the loading of all of the queued resource load requests.
-	void					flush();
 
-	/// Callback wrappers to member functions
-	void					loading_callback_wrapper(void* thiz, ResourceId name);
-	void					online_callback_wrapper(void* thiz, ResourceId name, void* resource);
+	void					flush_load_queue();
+	void					bring_loaded_online();
 
 private:
 
-	void					loading(ResourceId name);
 	void					online(ResourceId name, void* resource);
 
 private:
@@ -118,8 +118,8 @@ private:
 
 	MallocAllocator			m_allocator;
 	List<ResourceEntry>		m_resources;
-	
-	friend class			ResourceLoader;
+
+	Queue<ResourceId>		m_loading_queue;
 };
 
 } // namespace crown