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);
load_resource(r);
}
-void ResourceManager::load_resource(const Resource &r)
+void ResourceManager::load_resource(Resource &r)
{
ManagedResource &managed = get_item(resources, &r);
if(!managed.collection)
if(managed.loader)
return;
- managed.io = managed.collection->open_raw(managed.name);
- managed.loader = managed.resource->load(*managed.io);
+ managed.start_loading();
- queue.push_back(&managed);
+ 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)
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;
}
resource(&r),
collection(0),
io(0),
- loader(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),
if(finished)
{
- delete resource->loader;
- resource->loader = 0;
- delete resource->io;
- resource->io = 0;
+ resource->finish_loading();
resource = 0;
state = IDLE;
}