2 #include <msp/time/utils.h>
3 #include "resourcemanager.h"
4 #include "resourcewatcher.h"
11 ResourceManager::ResourceManager():
12 policy(LOAD_ON_DEMAND),
16 min_retain_frames(30),
21 ResourceManager::~ResourceManager()
25 while(!resources.empty())
26 resources.begin()->second.resource->set_manager(0);
29 void ResourceManager::set_loading_policy(LoadingPolicy p)
34 void ResourceManager::set_async_loads(bool a)
39 void ResourceManager::set_size_limit(UInt64 s)
44 void ResourceManager::set_min_retain_frames(unsigned f)
46 min_retain_frames = f;
49 void ResourceManager::set_max_retain_frames(unsigned f)
51 max_retain_frames = f;
54 void ResourceManager::add_resource(Resource &r)
56 insert_unique(resources, &r, ManagedResource(r));
59 void *ResourceManager::get_data_for_resource(const Resource &r)
61 return &get_item(resources, &r);
64 void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
66 ManagedResource &managed = get_item(resources, &r);
67 managed.collection = &c;
70 if(policy==LOAD_IMMEDIATELY)
74 void ResourceManager::load_resource(Resource &r)
76 ManagedResource &managed = get_item(resources, &r);
77 if(!managed.collection)
78 throw runtime_error("no location");
80 if(managed.state!=ManagedResource::NOT_LOADED)
85 managed.state = ManagedResource::LOAD_QUEUED;
86 queue.push_back(&managed);
90 managed.start_loading();
91 while(!managed.loader->process()) ;
92 managed.finish_loading(true);
96 void ResourceManager::resource_used(const Resource &r)
98 ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
99 if(managed->state==ManagedResource::NOT_LOADED && policy!=LOAD_MANUALLY)
100 load_resource(*managed->resource);
102 managed->last_used = frame;
103 if(max_retain_frames && !next_unload)
104 next_unload = frame+max_retain_frames+1;
107 void ResourceManager::remove_resource(Resource &r)
109 ManagedResource &managed = get_item(resources, &r);
110 ManagedResource::State state = managed.state;
111 if(state==ManagedResource::LOAD_QUEUED)
113 LoadQueue::iterator i = find(queue.begin(), queue.end(), &managed);
117 else if(state>ManagedResource::LOAD_QUEUED && state<ManagedResource::LOADED)
118 thread.remove_resource(managed);
119 remove_existing(resources, &r);
122 void ResourceManager::watch_resource(const Resource &r, ResourceWatcher &w)
124 get_item(resources, &r).add_watcher(w);
127 void ResourceManager::unwatch_resource(const Resource &r, ResourceWatcher &w)
129 get_item(resources, &r).remove_watcher(w);
132 void ResourceManager::tick()
136 bool do_unload = (frame>=next_unload);
140 if(thread.needs_work() && !queue.empty())
145 if(max_retain_frames && frame>=next_unload)
150 for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
151 if(i->second.state==ManagedResource::LOADED)
152 next_unload = min(next_unload, i->second.last_used);
153 next_unload = (next_unload<frame ? next_unload+max_retain_frames : 0);
161 void ResourceManager::dispatch_work()
163 queue.sort(age_order);
165 if(queue.front()->last_used+10<frame)
167 for(LoadQueue::iterator i=queue.begin(); i!=queue.end(); ++i)
168 (*i)->state = ManagedResource::NOT_LOADED;
173 while(thread.needs_work() && !queue.empty())
175 ManagedResource *managed = queue.front();
177 thread.add_resource(*managed);
181 void ResourceManager::unload_by_age()
183 unsigned unload_limit = frame-max_retain_frames;
185 for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
186 if(i->second.state==ManagedResource::LOADED && i->second.last_used<unload_limit)
190 void ResourceManager::unload_by_size()
192 unsigned unload_limit = frame-min_retain_frames;
194 while(get_total_data_size()>size_limit)
196 ManagedResource *best = 0;
197 UInt64 best_impact = 0;
198 for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
199 if(i->second.state==ManagedResource::LOADED && i->second.last_used<unload_limit)
201 UInt64 impact = i->second.data_size*(frame-i->second.last_used);
202 if(!best || impact>best_impact)
205 best_impact = impact;
216 UInt64 ResourceManager::get_total_data_size() const
219 for(ResourceMap::const_iterator i=resources.begin(); i!=resources.end(); ++i)
220 if(i->second.state==ManagedResource::LOADED)
221 total += i->second.data_size;
225 bool ResourceManager::age_order(ManagedResource *mr1, ManagedResource *mr2)
227 return mr1->last_used>mr2->last_used;
231 ResourceManager::ManagedResource::ManagedResource(Resource &r):
241 void ResourceManager::ManagedResource::start_loading()
243 io = collection->open_raw(name);
244 loader = resource->load(*io);
249 throw logic_error("no loader created");
254 bool ResourceManager::ManagedResource::process(bool sync)
256 while(state!=LOAD_FINISHED && loader->needs_sync()==sync)
257 if(loader->process())
258 state = LOAD_FINISHED;
260 return state==LOAD_FINISHED;
263 void ResourceManager::ManagedResource::finish_loading(bool successful)
273 data_size = resource->get_data_size();
275 for(vector<ResourceWatcher *>::const_iterator i=watchers.begin(); i!=watchers.end(); ++i)
276 (*i)->resource_loaded(*resource);
285 void ResourceManager::ManagedResource::finish_loading()
287 finish_loading(state==LOAD_FINISHED);
290 void ResourceManager::ManagedResource::unload()
295 for(vector<ResourceWatcher *>::const_iterator i=watchers.begin(); i!=watchers.end(); ++i)
296 (*i)->resource_unloaded(*resource);
299 void ResourceManager::ManagedResource::add_watcher(ResourceWatcher &w)
301 if(find(watchers.begin(), watchers.end(), &w)==watchers.end())
302 watchers.push_back(&w);
305 void ResourceManager::ManagedResource::remove_watcher(ResourceWatcher &w)
307 vector<ResourceWatcher *>::iterator end = remove(watchers.begin(), watchers.end(), &w);
308 if(end!=watchers.end())
309 watchers.erase(end, watchers.end());
313 ResourceManager::LoadingThread::LoadingThread():
322 void ResourceManager::LoadingThread::main()
324 bool wait_for_work = false;
330 if(ManagedResource *managed = front(async_queue))
332 managed->process(false);
334 MutexLock lock(queue_mutex);
335 sync_queue.splice(sync_queue.end(), async_queue, async_queue.begin());
336 wait_for_work = async_queue.empty();
339 wait_for_work = true;
343 ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &queue)
345 MutexLock lock(queue_mutex);
349 return queue.front();
352 void ResourceManager::LoadingThread::add_resource(ManagedResource &r)
356 MutexLock lock(queue_mutex);
357 if(r.loader->needs_sync())
358 sync_queue.push_back(&r);
361 bool was_empty = async_queue.empty();
362 async_queue.push_back(&r);
370 void ResourceManager::LoadingThread::remove_resource(ManagedResource &r)
372 while(!try_remove_resource(r))
373 Time::sleep(Time::msec);
378 bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r)
380 MutexLock lock(queue_mutex);
382 LoadQueue::iterator i = find(async_queue.begin(), async_queue.end(), &r);
383 if(i==async_queue.end())
385 i = find(sync_queue.begin(), sync_queue.end(), &r);
386 if(i!=sync_queue.end())
389 else if(i==async_queue.begin())
392 async_queue.erase(i);
397 bool ResourceManager::LoadingThread::sync()
400 MutexLock lock(queue_mutex);
401 unsigned async_size = async_queue.size();
402 if(async_size==0 && size==capacity)
404 else if(async_size>2 && capacity>2)
408 bool any_finished = false;
409 while(ManagedResource *managed = front(sync_queue))
411 if(managed->process(true))
413 managed->finish_loading();
417 MutexLock lock(queue_mutex);
418 sync_queue.pop_front();
422 MutexLock lock(queue_mutex);
423 bool was_empty = async_queue.empty();
424 async_queue.splice(async_queue.end(), sync_queue, sync_queue.begin());
433 void ResourceManager::LoadingThread::terminate()