X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fresourcemanager.cpp;h=4b72685d4d4ba6f4594a2349101cc253b9ecd36f;hp=733cfaff8c4c37ba5ae1ffbd605ceb3f8d6a58df;hb=HEAD;hpb=da5629982b65a4cbf31abc30a0cf930801fcc940 diff --git a/source/resourcemanager.cpp b/source/resourcemanager.cpp deleted file mode 100644 index 733cfaff..00000000 --- a/source/resourcemanager.cpp +++ /dev/null @@ -1,502 +0,0 @@ -#include -#include -#include -#include -#include -#include "resourcemanager.h" -#include "resourcewatcher.h" - -using namespace std; - -namespace Msp { -namespace GL { - -resource_load_error::resource_load_error(const string &name, const string &err): - runtime_error(format("%s: %s", name, err)) -{ } - -resource_load_error::resource_load_error(const string &name, const exception &exc): - runtime_error(format("%s: %s: %s", name, Debug::demangle(typeid(exc).name()), exc.what())) -{ } - - -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) -{ } - -ResourceManager::~ResourceManager() -{ - thread.terminate(); - - while(!resources.empty()) - resources.begin()->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) -{ - set_resource_location(r, ResourceLocation(c, n)); -} - -void ResourceManager::set_resource_location(Resource &r, const ResourceLocation &l) -{ - ManagedResource &managed = get_item(resources, &r); - managed.location = l; - - if(policy==LOAD_IMMEDIATELY) - load_resource(r); -} - -const ResourceManager::ResourceLocation *ResourceManager::get_resource_location(const Resource &r) const -{ - const ManagedResource &managed = get_item(resources, &r); - return managed.location.collection ? &managed.location : 0; -} - -void ResourceManager::load_resource(Resource &r) -{ - ManagedResource &managed = get_item(resources, &r); - if(!managed.location.collection) - throw runtime_error("no location"); - - if(managed.state!=ManagedResource::NOT_LOADED) - return; - - if(async_loads) - { - managed.state = ManagedResource::LOAD_QUEUED; - queue.push_back(&managed); - } - else - { - managed.start_loading(); - while(!managed.loader->process()) ; - managed.finish_loading(true); - } -} - -bool ResourceManager::is_resource_loaded(const Resource &r) const -{ - ManagedResource *managed = reinterpret_cast(r.get_manager_data()); - return managed ? managed->state==ManagedResource::LOADED : false; -} - -void ResourceManager::resource_used(const Resource &r) -{ - ManagedResource *managed = reinterpret_cast(r.get_manager_data()); - if(!managed) - return; - if(managed->state==ManagedResource::NOT_LOADED && policy!=LOAD_MANUALLY) - load_resource(*managed->resource); - - managed->last_used = frame; - if(max_retain_frames && !next_unload) - next_unload = frame+max_retain_frames+1; -} - -void ResourceManager::remove_resource(Resource &r) -{ - ManagedResource &managed = get_item(resources, &r); - ManagedResource::State state = managed.state; - if(state==ManagedResource::LOAD_QUEUED) - { - LoadQueue::iterator i = find(queue.begin(), queue.end(), &managed); - if(i!=queue.end()) - queue.erase(i); - } - else if(state>ManagedResource::LOAD_QUEUED && state=next_unload); - if(thread.sync()) - do_unload = true; - - if(thread.needs_work() && !queue.empty()) - dispatch_work(); - - if(do_unload) - { - if(max_retain_frames && frame>=next_unload) - { - unload_by_age(); - - next_unload = frame; - for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i) - if(i->second.state==ManagedResource::LOADED) - next_unload = min(next_unload, i->second.last_used); - next_unload = (next_unloadlast_used+10state = ManagedResource::NOT_LOADED; - queue.clear(); - return; - } - - while(thread.needs_work() && !queue.empty()) - { - ManagedResource *managed = queue.front(); - queue.pop_front(); - thread.add_resource(*managed); - } -} - -void ResourceManager::unload_by_age() -{ - unsigned unload_limit = frame-max_retain_frames; - - for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i) - if(i->second.state==ManagedResource::LOADED && i->second.last_usedsecond.unload(); -} - -void ResourceManager::unload_by_size() -{ - unsigned unload_limit = frame-min_retain_frames; - - while(get_total_data_size()>size_limit) - { - ManagedResource *best = 0; - UInt64 best_impact = 0; - for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i) - if(i->second.state==ManagedResource::LOADED && i->second.last_usedsecond.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.state==ManagedResource::LOADED) - total += i->second.data_size; - return total; -} - -bool ResourceManager::age_order(ManagedResource *mr1, ManagedResource *mr2) -{ - return mr1->last_used>mr2->last_used; -} - - -ResourceManager::ResourceLocation::ResourceLocation(): - collection(0) -{ } - -ResourceManager::ResourceLocation::ResourceLocation(DataFile::Collection &c, const string &n): - collection(&c), - name(n) -{ } - - -ResourceManager::ManagedResource::ManagedResource(Resource &r): - resource(&r), - io(0), - loader(0), - state(NOT_LOADED), - last_used(0), - data_size(0) -{ } - -void ResourceManager::ManagedResource::start_loading() -{ - io = location.collection->open_raw(location.name); - if(!io) - throw resource_load_error(location.name, "open failed"); - - loader = resource->load(*io); - if(!loader) - { - delete io; - io = 0; - throw logic_error("no loader created"); - } - state = LOADING; -} - -bool ResourceManager::ManagedResource::process(bool sync) -{ - while(state!=LOAD_FINISHED && loader->needs_sync()==sync) - if(loader->process()) - state = LOAD_FINISHED; - - return state==LOAD_FINISHED; -} - -void ResourceManager::ManagedResource::finish_loading(bool successful) -{ - delete loader; - loader = 0; - delete io; - io = 0; - - if(successful) - { - state = LOADED; - data_size = resource->get_data_size(); - - for(vector::const_iterator i=watchers.begin(); i!=watchers.end(); ++i) - (*i)->resource_loaded(*resource); - } - else - { - resource->unload(); - state = NOT_LOADED; - } -} - -void ResourceManager::ManagedResource::finish_loading() -{ - finish_loading(state==LOAD_FINISHED); -} - -void ResourceManager::ManagedResource::unload() -{ - resource->unload(); - state = NOT_LOADED; - - for(vector::const_iterator i=watchers.begin(); i!=watchers.end(); ++i) - (*i)->resource_unloaded(*resource); -} - -void ResourceManager::ManagedResource::add_watcher(ResourceWatcher &w) -{ - if(find(watchers.begin(), watchers.end(), &w)==watchers.end()) - watchers.push_back(&w); -} - -void ResourceManager::ManagedResource::remove_watcher(ResourceWatcher &w) -{ - vector::iterator end = remove(watchers.begin(), watchers.end(), &w); - if(end!=watchers.end()) - watchers.erase(end, watchers.end()); -} - - -ResourceManager::LoadingThread::LoadingThread(): - sem(1), - capacity(2), - size(0), - done(false) -{ - launch(); -} - -void ResourceManager::LoadingThread::main() -{ - bool wait_for_work = false; - while(!done) - { - if(wait_for_work) - sem.wait(); - - if(ManagedResource *managed = front(async_queue)) - { - try - { - managed->process(false); - } - catch(const exception &e) - { - MutexLock lock(queue_mutex); - error_queue.push_back(resource_load_error(managed->location.name, e)); - managed->state = ManagedResource::LOAD_ERROR; - } - - MutexLock lock(queue_mutex); - sync_queue.splice(sync_queue.end(), async_queue, async_queue.begin()); - wait_for_work = async_queue.empty(); - } - else - wait_for_work = true; - } -} - -ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &queue) -{ - MutexLock lock(queue_mutex); - if(queue.empty()) - return 0; - - return queue.front(); -} - -void ResourceManager::LoadingThread::add_resource(ManagedResource &r) -{ - r.start_loading(); - - MutexLock lock(queue_mutex); - if(r.loader->needs_sync()) - sync_queue.push_back(&r); - else - { - bool was_empty = async_queue.empty(); - async_queue.push_back(&r); - if(was_empty) - sem.signal(); - } - - ++size; -} - -void ResourceManager::LoadingThread::remove_resource(ManagedResource &r) -{ - while(!try_remove_resource(r)) - Time::sleep(Time::msec); - - r.finish_loading(); -} - -bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r) -{ - MutexLock lock(queue_mutex); - - LoadQueue::iterator i = find(async_queue.begin(), async_queue.end(), &r); - if(i==async_queue.end()) - { - i = find(sync_queue.begin(), sync_queue.end(), &r); - if(i!=sync_queue.end()) - sync_queue.erase(i); - } - else if(i==async_queue.begin()) - return false; - else - async_queue.erase(i); - - return true; -} - -bool ResourceManager::LoadingThread::sync() -{ - { - MutexLock lock(queue_mutex); - - if(!error_queue.empty()) - { - resource_load_error err = error_queue.front(); - error_queue.pop_front(); - throw err; - } - - unsigned async_size = async_queue.size(); - if(async_size==0 && size==capacity) - ++capacity; - else if(async_size>2 && capacity>2) - --capacity; - } - - bool any_finished = false; - while(ManagedResource *managed = front(sync_queue)) - { - if(managed->state==ManagedResource::LOAD_ERROR || managed->process(true)) - { - managed->finish_loading(); - any_finished = true; - --size; - - MutexLock lock(queue_mutex); - sync_queue.pop_front(); - } - else - { - MutexLock lock(queue_mutex); - bool was_empty = async_queue.empty(); - async_queue.splice(async_queue.end(), sync_queue, sync_queue.begin()); - if(was_empty) - sem.signal(); - } - } - - return any_finished; -} - -void ResourceManager::LoadingThread::terminate() -{ - done = true; - sem.signal(); - join(); - async_queue.clear(); - sync_queue.clear(); -} - -} // namespace GL -} // namespace Msp