-#include <msp/time/utils.h>
-#include "resourcemanager.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-ResourceManager::ResourceManager():
- policy(LOAD_ON_DEMAND),
- async_loads(true),
- size_limit(0),
- frame(0),
- min_retain_frames(30),
- max_retain_frames(0),
- next_unload(0),
- thread(*this)
-{ }
-
-ResourceManager::~ResourceManager()
-{
- thread.terminate();
-
- for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
- i->second.resource->set_manager(0);
-}
-
-void ResourceManager::set_loading_policy(LoadingPolicy p)
-{
- policy = p;
-}
-
-void ResourceManager::set_async_loads(bool a)
-{
- async_loads = a;
-}
-
-void ResourceManager::set_size_limit(UInt64 s)
-{
- size_limit = s;
-}
-
-void ResourceManager::set_min_retain_frames(unsigned f)
-{
- min_retain_frames = f;
-}
-
-void ResourceManager::set_max_retain_frames(unsigned f)
-{
- max_retain_frames = f;
-}
-
-void ResourceManager::add_resource(Resource &r)
-{
- insert_unique(resources, &r, ManagedResource(r));
-}
-
-void *ResourceManager::get_data_for_resource(const Resource &r)
-{
- return &get_item(resources, &r);
-}
-
-void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
-{
- ManagedResource &managed = get_item(resources, &r);
- managed.collection = &c;
- managed.name = n;
-
- if(policy==LOAD_IMMEDIATELY)
- load_resource(r);
-}
-
-void ResourceManager::load_resource(Resource &r)
-{
- ManagedResource &managed = get_item(resources, &r);
- if(!managed.collection)
- throw runtime_error("no location");
-
- if(managed.loader)
- return;
-
- managed.start_loading();
-
- if(async_loads)
- queue.push_back(&managed);
- else
- {
- while(!managed.loader->process()) ;
- managed.finish_loading();
- }
-}
-
-void ResourceManager::resource_used(const Resource &r)
-{
- ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
- if(!managed->loaded && !managed->loader && policy!=LOAD_MANUALLY)
- load_resource(*managed->resource);
-
- managed->last_used = frame;
- if(max_retain_frames && !next_unload)
- next_unload = frame+max_retain_frames;
-}
-
-void ResourceManager::remove_resource(Resource &r)
-{
- ManagedResource *loading = thread.get_resource();
- if(loading && loading->resource==&r)
- thread.set_resource(0);
-
- remove_existing(resources, &r);
-}
-
-void ResourceManager::tick()
-{
- LoadingThread::State thread_state = thread.get_state();
- bool check_total_size = false;
- if(thread_state==LoadingThread::SYNC_PENDING)
- {
- thread.sync();
- check_total_size = true;
- }
- else if(thread_state==LoadingThread::IDLE && !queue.empty())
- {
- ManagedResource *managed = queue.front();
- queue.pop_front();
- thread.set_resource(managed);
- }
-
- ++frame;
- if(frame==next_unload)
- {
- unsigned unload_limit = frame-max_retain_frames;
- next_unload = 0;
-
- for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
- if(i->second.loaded)
- {
- if(i->second.last_used<=unload_limit)
- i->second.unload();
- else if(!next_unload || i->second.last_used<next_unload)
- next_unload = i->second.last_used;
- }
-
- if(next_unload)
- next_unload += max_retain_frames;
- }
-
- if(check_total_size)
- {
- while(get_total_data_size()>size_limit)
- {
- unsigned unload_limit = frame-min_retain_frames;
- ManagedResource *best = 0;
- UInt64 best_impact = 0;
- for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
- if(i->second.loaded && i->second.last_used<unload_limit)
- {
- UInt64 impact = i->second.data_size*(frame-i->second.last_used);
- if(!best || impact<best_impact)
- {
- best = &i->second;
- best_impact = impact;
- }
- }
-
- if(!best)
- break;
-
- best->unload();
- }
- }
-}
-
-UInt64 ResourceManager::get_total_data_size() const
-{
- UInt64 total = 0;
- for(ResourceMap::const_iterator i=resources.begin(); i!=resources.end(); ++i)
- if(i->second.loaded)
- total += i->second.data_size;
- return total;
-}
-
-
-ResourceManager::ManagedResource::ManagedResource(Resource &r):
- resource(&r),
- collection(0),
- io(0),
- loader(0),
- loaded(false),
- last_used(0),
- data_size(0)
-{ }
-
-void ResourceManager::ManagedResource::start_loading()
-{
- io = collection->open_raw(name);
- loader = resource->load(*io);
- if(!loader)
- {
- delete io;
- io = 0;
- throw logic_error("no loader created");
- }
-}
-
-void ResourceManager::ManagedResource::finish_loading()
-{
- delete loader;
- loader = 0;
- loaded = true;
- delete io;
- io = 0;
- data_size = resource->get_data_size();
-}
-
-void ResourceManager::ManagedResource::unload()
-{
- resource->unload();
- loaded = false;
-}
-
-
-ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
- manager(m),
- sem(1),
- resource(0),
- state(IDLE)
-{
- launch();
-}
-
-void ResourceManager::LoadingThread::main()
-{
- while(state!=TERMINATING)
- {
- sem.wait();
-
- if(state==BUSY)
- {
- Resource::AsyncLoader *ldr = resource->loader;
- bool finished = false;
- while(!finished && !ldr->needs_sync())
- finished = ldr->process();
-
- if(finished)
- state = LOAD_FINISHED;
- else
- state = SYNC_PENDING;
- }
- }
-}
-
-void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
-{
- if(state!=IDLE)
- {
- while(state==BUSY) ;
- // Force finish to clean up the loader
- state = LOAD_FINISHED;
- sync();
- }
-
- resource = r;
- state = BUSY;
- sem.signal();
-}
-
-void ResourceManager::LoadingThread::sync()
-{
- State s = state;
- bool finished = (s==LOAD_FINISHED);
- if(s==SYNC_PENDING)
- {
- Resource::AsyncLoader *ldr = resource->loader;
- while(!finished && ldr->needs_sync())
- finished = ldr->process();
-
- if(!finished)
- {
- state = BUSY;
- sem.signal();
- return;
- }
- }
-
- if(finished)
- {
- resource->finish_loading();
- resource = 0;
- state = IDLE;
- }
-}
-
-void ResourceManager::LoadingThread::terminate()
-{
- while(state==BUSY) ;
- state = TERMINATING;
- sem.signal();
- join();
-}
-
-} // namespace GL
-} // namespace Msp