X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fresourcemanager.cpp;h=3456ac887a58f2e77d8e67ca7cf328a6fec8b1be;hb=3c09b67afba6d560eab5817016a98268e1544bc4;hp=98a49744a702c2ecaf7db14a99c0afbf4da6158a;hpb=20703b6d4dfd0836cdb787bd416d4ae9bf010602;p=libs%2Fgl.git diff --git a/source/resourcemanager.cpp b/source/resourcemanager.cpp index 98a49744..3456ac88 100644 --- a/source/resourcemanager.cpp +++ b/source/resourcemanager.cpp @@ -1,5 +1,7 @@ +#include #include #include "resourcemanager.h" +#include "resourcewatcher.h" using namespace std; @@ -9,6 +11,11 @@ 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) { } @@ -20,11 +27,41 @@ ResourceManager::~ResourceManager() 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); @@ -35,7 +72,7 @@ void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c 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) @@ -44,10 +81,26 @@ void ResourceManager::load_resource(const Resource &r) if(managed.loader) return; - managed.io = managed.collection->open_raw(managed.name); - managed.loader = managed.resource->load(*managed.io); + 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(r.get_manager_data()); + if(!managed->loaded && !managed->loader && policy!=LOAD_MANUALLY) + load_resource(*managed->resource); - queue.push_back(&managed); + managed->last_used = frame; + if(max_retain_frames && !next_unload) + next_unload = frame+max_retain_frames; } void ResourceManager::remove_resource(Resource &r) @@ -59,17 +112,84 @@ void ResourceManager::remove_resource(Resource &r) remove_existing(resources, &r); } +void ResourceManager::watch_resource(const Resource &r, ResourceWatcher &w) +{ + get_item(resources, &r).add_watcher(w); +} + +void ResourceManager::unwatch_resource(const Resource &r, ResourceWatcher &w) +{ + get_item(resources, &r).remove_watcher(w); +} + void ResourceManager::tick() { LoadingThread::State thread_state = thread.get_state(); - if(thread_state==LoadingThread::SYNC_PENDING) + bool check_total_size = false; + if(thread_state==LoadingThread::SYNC_PENDING || thread_state==LoadingThread::LOAD_FINISHED) + { 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_usedsecond.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_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.loaded) + total += i->second.data_size; + return total; } @@ -77,9 +197,59 @@ ResourceManager::ManagedResource::ManagedResource(Resource &r): 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(); + + for(vector::const_iterator i=watchers.begin(); i!=watchers.end(); ++i) + (*i)->resource_loaded(*resource); +} + +void ResourceManager::ManagedResource::unload() +{ + resource->unload(); + loaded = false; + + 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(ResourceManager &m): manager(m), @@ -146,10 +316,7 @@ void ResourceManager::LoadingThread::sync() if(finished) { - delete resource->loader; - resource->loader = 0; - delete resource->io; - resource->io = 0; + resource->finish_loading(); resource = 0; state = IDLE; }