X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fresourcemanager.cpp;h=4b72685d4d4ba6f4594a2349101cc253b9ecd36f;hp=f008fd272c212462d6db90bdfccc020b7298015a;hb=71240e5c5ef7165313664ee9fe81df95c0eff10b;hpb=5f84c8caeb789571503b5491f941c8ec31b700fe diff --git a/source/resourcemanager.cpp b/source/resourcemanager.cpp index f008fd27..4b72685d 100644 --- a/source/resourcemanager.cpp +++ b/source/resourcemanager.cpp @@ -4,13 +4,18 @@ #include #include #include "resourcemanager.h" -#include "resourcewatcher.h" +#include "resources.h" +#include "resourceobserver.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())) { } @@ -19,6 +24,7 @@ resource_load_error::resource_load_error(const string &name, const exception &ex ResourceManager::ResourceManager(): policy(LOAD_ON_DEMAND), async_loads(true), + total_data_size(0), size_limit(0), frame(0), min_retain_frames(30), @@ -61,12 +67,20 @@ void ResourceManager::set_max_retain_frames(unsigned f) void ResourceManager::add_resource(Resource &r) { + MutexLock lock(map_mutex); insert_unique(resources, &r, ManagedResource(r)); } -void *ResourceManager::get_data_for_resource(const Resource &r) +const ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r) const +{ + MutexLock lock(map_mutex); + return get_item(resources, &r); +} + +ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r) { - return &get_item(resources, &r); + MutexLock lock(map_mutex); + return get_item(resources, &r); } void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n) @@ -76,8 +90,11 @@ void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c void ResourceManager::set_resource_location(Resource &r, const ResourceLocation &l) { - ManagedResource &managed = get_item(resources, &r); - managed.location = l; + { + MutexLock lock(map_mutex); + ManagedResource &managed = get_item(resources, &r); + managed.location = l; + } if(policy==LOAD_IMMEDIATELY) load_resource(r); @@ -85,13 +102,13 @@ void ResourceManager::set_resource_location(Resource &r, const ResourceLocation const ResourceManager::ResourceLocation *ResourceManager::get_resource_location(const Resource &r) const { - const ManagedResource &managed = get_item(resources, &r); + const ManagedResource &managed = get_managed_resource(r); return managed.location.collection ? &managed.location : 0; } void ResourceManager::load_resource(Resource &r) { - ManagedResource &managed = get_item(resources, &r); + ManagedResource &managed = get_managed_resource(r); if(!managed.location.collection) throw runtime_error("no location"); @@ -101,13 +118,16 @@ void ResourceManager::load_resource(Resource &r) if(async_loads) { managed.state = ManagedResource::LOAD_QUEUED; - queue.push_back(&managed); + LoadQueue::iterator i; + for(i=queue.begin(); (i!=queue.end() && (*i)->load_priority>=managed.load_priority); ++i) ; + queue.insert(i, &managed); } else { managed.start_loading(); while(!managed.loader->process()) ; managed.finish_loading(true); + total_data_size += managed.data_size; } } @@ -120,6 +140,8 @@ bool ResourceManager::is_resource_loaded(const Resource &r) const 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); @@ -130,7 +152,7 @@ void ResourceManager::resource_used(const Resource &r) void ResourceManager::remove_resource(Resource &r) { - ManagedResource &managed = get_item(resources, &r); + ManagedResource &managed = get_managed_resource(r); ManagedResource::State state = managed.state; if(state==ManagedResource::LOAD_QUEUED) { @@ -140,17 +162,22 @@ void ResourceManager::remove_resource(Resource &r) } else if(state>ManagedResource::LOAD_QUEUED && state::const_iterator i=managed.observers.begin(); i!=managed.observers.end(); ++i) + (*i)->resource_removed(r); + + MutexLock lock(map_mutex); remove_existing(resources, &r); } -void ResourceManager::watch_resource(const Resource &r, ResourceWatcher &w) +void ResourceManager::observe_resource(const Resource &r, ResourceObserver &w) { - get_item(resources, &r).add_watcher(w); + get_managed_resource(r).add_observer(w); } -void ResourceManager::unwatch_resource(const Resource &r, ResourceWatcher &w) +void ResourceManager::unobserve_resource(const Resource &r, ResourceObserver &w) { - get_item(resources, &r).remove_watcher(w); + get_managed_resource(r).remove_observer(w); } void ResourceManager::tick() @@ -159,13 +186,17 @@ void ResourceManager::tick() bool do_unload = (frame>=next_unload); if(thread.sync()) + { + total_data_size += thread.get_and_reset_loaded_data_size(); do_unload = true; + } if(thread.needs_work() && !queue.empty()) dispatch_work(); if(do_unload) { + MutexLock lock(map_mutex); if(max_retain_frames && frame>=next_unload) { unload_by_age(); @@ -208,14 +239,17 @@ void ResourceManager::unload_by_age() for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i) if(i->second.state==ManagedResource::LOADED && i->second.last_usedsecond.unload(); + total_data_size -= i->second.data_size; + } } void ResourceManager::unload_by_size() { unsigned unload_limit = frame-min_retain_frames; - while(get_total_data_size()>size_limit) + while(total_data_size>size_limit) { ManagedResource *best = 0; UInt64 best_impact = 0; @@ -234,18 +268,10 @@ void ResourceManager::unload_by_size() break; best->unload(); + total_data_size -= best->data_size; } } -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; @@ -264,6 +290,7 @@ ResourceManager::ResourceLocation::ResourceLocation(DataFile::Collection &c, con ResourceManager::ManagedResource::ManagedResource(Resource &r): resource(&r), + load_priority(r.get_load_priority()), io(0), loader(0), state(NOT_LOADED), @@ -274,7 +301,11 @@ ResourceManager::ManagedResource::ManagedResource(Resource &r): void ResourceManager::ManagedResource::start_loading() { io = location.collection->open_raw(location.name); - loader = resource->load(*io); + if(!io) + throw resource_load_error(location.name, "open failed"); + + const Resources *res = dynamic_cast(location.collection); + loader = resource->load(*io, res); if(!loader) { delete io; @@ -305,7 +336,7 @@ void ResourceManager::ManagedResource::finish_loading(bool successful) state = LOADED; data_size = resource->get_data_size(); - for(vector::const_iterator i=watchers.begin(); i!=watchers.end(); ++i) + for(vector::const_iterator i=observers.begin(); i!=observers.end(); ++i) (*i)->resource_loaded(*resource); } else @@ -325,21 +356,21 @@ void ResourceManager::ManagedResource::unload() resource->unload(); state = NOT_LOADED; - for(vector::const_iterator i=watchers.begin(); i!=watchers.end(); ++i) + for(vector::const_iterator i=observers.begin(); i!=observers.end(); ++i) (*i)->resource_unloaded(*resource); } -void ResourceManager::ManagedResource::add_watcher(ResourceWatcher &w) +void ResourceManager::ManagedResource::add_observer(ResourceObserver &w) { - if(find(watchers.begin(), watchers.end(), &w)==watchers.end()) - watchers.push_back(&w); + if(find(observers.begin(), observers.end(), &w)==observers.end()) + observers.push_back(&w); } -void ResourceManager::ManagedResource::remove_watcher(ResourceWatcher &w) +void ResourceManager::ManagedResource::remove_observer(ResourceObserver &w) { - vector::iterator end = remove(watchers.begin(), watchers.end(), &w); - if(end!=watchers.end()) - watchers.erase(end, watchers.end()); + vector::iterator end = remove(observers.begin(), observers.end(), &w); + if(end!=observers.end()) + observers.erase(end, observers.end()); } @@ -347,6 +378,7 @@ ResourceManager::LoadingThread::LoadingThread(): sem(1), capacity(2), size(0), + loaded_data_size(0), done(false) { launch(); @@ -382,13 +414,13 @@ void ResourceManager::LoadingThread::main() } } -ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &queue) +ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &que) { MutexLock lock(queue_mutex); - if(queue.empty()) + if(que.empty()) return 0; - return queue.front(); + return que.front(); } void ResourceManager::LoadingThread::add_resource(ManagedResource &r) @@ -415,6 +447,11 @@ void ResourceManager::LoadingThread::remove_resource(ManagedResource &r) Time::sleep(Time::msec); r.finish_loading(); + if(r.state==ManagedResource::LOADED) + { + MutexLock lock(data_size_mutex); + loaded_data_size += r.data_size; + } } bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r) @@ -426,12 +463,18 @@ bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r) { i = find(sync_queue.begin(), sync_queue.end(), &r); if(i!=sync_queue.end()) + { sync_queue.erase(i); + --size; + } } else if(i==async_queue.begin()) return false; else + { async_queue.erase(i); + --size; + } return true; } @@ -461,6 +504,11 @@ bool ResourceManager::LoadingThread::sync() if(managed->state==ManagedResource::LOAD_ERROR || managed->process(true)) { managed->finish_loading(); + if(managed->state==ManagedResource::LOADED) + { + MutexLock lock(data_size_mutex); + loaded_data_size += managed->data_size; + } any_finished = true; --size; @@ -480,6 +528,14 @@ bool ResourceManager::LoadingThread::sync() return any_finished; } +UInt64 ResourceManager::LoadingThread::get_and_reset_loaded_data_size() +{ + MutexLock lock(data_size_mutex); + UInt64 result = loaded_data_size; + loaded_data_size = 0; + return result; +} + void ResourceManager::LoadingThread::terminate() { done = true;