X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fresourcemanager.cpp;h=999b86c190451dae5a8d33967a3c461c5282862c;hb=946266e823c07025f115b5e4f5523b496dcb393e;hp=cc69b895aa2ecd33196df0b087e0d3521ee2999c;hpb=47abe7c9e1633ca65f910a4db340724117a6f6e5;p=libs%2Fgl.git diff --git a/source/resourcemanager.cpp b/source/resourcemanager.cpp index cc69b895..999b86c1 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) { } @@ -16,8 +23,8 @@ ResourceManager::~ResourceManager() { thread.terminate(); - for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i) - i->second.resource->set_manager(0); + while(!resources.empty()) + resources.begin()->second.resource->set_manager(0); } void ResourceManager::set_loading_policy(LoadingPolicy p) @@ -30,6 +37,21 @@ 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)); @@ -56,15 +78,17 @@ void ResourceManager::load_resource(Resource &r) if(!managed.collection) throw runtime_error("no location"); - if(managed.loader) + if(managed.state!=ManagedResource::NOT_LOADED) return; - managed.start_loading(); - if(async_loads) + { + managed.state = ManagedResource::LOAD_QUEUED; queue.push_back(&managed); + } else { + managed.start_loading(); while(!managed.loader->process()) ; managed.finish_loading(); } @@ -73,8 +97,12 @@ void ResourceManager::load_resource(Resource &r) void ResourceManager::resource_used(const Resource &r) { ManagedResource *managed = reinterpret_cast(r.get_manager_data()); - if(!managed->loaded && !managed->loader && policy!=LOAD_MANUALLY) + 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; } void ResourceManager::remove_resource(Resource &r) @@ -86,17 +114,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.state==ManagedResource::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.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; } @@ -105,7 +200,9 @@ ResourceManager::ManagedResource::ManagedResource(Resource &r): collection(0), io(0), loader(0), - loaded(false) + state(NOT_LOADED), + last_used(0), + data_size(0) { } void ResourceManager::ManagedResource::start_loading() @@ -118,15 +215,42 @@ void ResourceManager::ManagedResource::start_loading() io = 0; throw logic_error("no loader created"); } + state = LOADING; } void ResourceManager::ManagedResource::finish_loading() { delete loader; loader = 0; - loaded = true; + state = LOADED; 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(); + 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()); } @@ -171,8 +295,12 @@ void ResourceManager::LoadingThread::set_resource(ManagedResource *r) } resource = r; - state = BUSY; - sem.signal(); + if(resource) + { + resource->start_loading(); + state = BUSY; + sem.signal(); + } } void ResourceManager::LoadingThread::sync()