]> git.tdb.fi Git - libs/gl.git/blob - source/resourcemanager.cpp
Implement manual loading policy and async flag
[libs/gl.git] / source / resourcemanager.cpp
1 #include <msp/time/utils.h>
2 #include "resourcemanager.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace GL {
8
9 ResourceManager::ResourceManager():
10         policy(LOAD_ON_DEMAND),
11         async_loads(true),
12         thread(*this)
13 { }
14
15 ResourceManager::~ResourceManager()
16 {
17         thread.terminate();
18
19         for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
20                 i->second.resource->set_manager(0);
21 }
22
23 void ResourceManager::set_loading_policy(LoadingPolicy p)
24 {
25         policy = p;
26 }
27
28 void ResourceManager::set_async_loads(bool a)
29 {
30         async_loads = a;
31 }
32
33 void ResourceManager::add_resource(Resource &r)
34 {
35         insert_unique(resources, &r, ManagedResource(r));
36 }
37
38 void *ResourceManager::get_data_for_resource(const Resource &r)
39 {
40         return &get_item(resources, &r);
41 }
42
43 void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
44 {
45         ManagedResource &managed = get_item(resources, &r);
46         managed.collection = &c;
47         managed.name = n;
48
49         if(policy==LOAD_IMMEDIATELY)
50                 load_resource(r);
51 }
52
53 void ResourceManager::load_resource(Resource &r)
54 {
55         ManagedResource &managed = get_item(resources, &r);
56         if(!managed.collection)
57                 throw runtime_error("no location");
58
59         if(managed.loader)
60                 return;
61
62         managed.start_loading();
63
64         if(async_loads)
65                 queue.push_back(&managed);
66         else
67         {
68                 while(!managed.loader->process()) ;
69                 managed.finish_loading();
70         }
71 }
72
73 void ResourceManager::resource_used(const Resource &r)
74 {
75         ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
76         if(!managed->loaded && !managed->loader && policy!=LOAD_MANUALLY)
77                 load_resource(*managed->resource);
78 }
79
80 void ResourceManager::remove_resource(Resource &r)
81 {
82         ManagedResource *loading = thread.get_resource();
83         if(loading && loading->resource==&r)
84                 thread.set_resource(0);
85
86         remove_existing(resources, &r);
87 }
88
89 void ResourceManager::tick()
90 {
91         LoadingThread::State thread_state = thread.get_state();
92         if(thread_state==LoadingThread::SYNC_PENDING)
93                 thread.sync();
94         else if(thread_state==LoadingThread::IDLE && !queue.empty())
95         {
96                 ManagedResource *managed = queue.front();
97                 queue.pop_front();
98                 thread.set_resource(managed);
99         }
100 }
101
102
103 ResourceManager::ManagedResource::ManagedResource(Resource &r):
104         resource(&r),
105         collection(0),
106         io(0),
107         loader(0),
108         loaded(false)
109 { }
110
111 void ResourceManager::ManagedResource::start_loading()
112 {
113         io = collection->open_raw(name);
114         loader = resource->load(*io);
115         if(!loader)
116         {
117                 delete io;
118                 io = 0;
119                 throw logic_error("no loader created");
120         }
121 }
122
123 void ResourceManager::ManagedResource::finish_loading()
124 {
125         delete loader;
126         loader = 0;
127         loaded = true;
128         delete io;
129         io = 0;
130 }
131
132
133 ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
134         manager(m),
135         sem(1),
136         resource(0),
137         state(IDLE)
138 {
139         launch();
140 }
141
142 void ResourceManager::LoadingThread::main()
143 {
144         while(state!=TERMINATING)
145         {
146                 sem.wait();
147
148                 if(state==BUSY)
149                 {
150                         Resource::AsyncLoader *ldr = resource->loader;
151                         bool finished = false;
152                         while(!finished && !ldr->needs_sync())
153                                 finished = ldr->process();
154
155                         if(finished)
156                                 state = LOAD_FINISHED;
157                         else
158                                 state = SYNC_PENDING;
159                 }
160         }
161 }
162
163 void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
164 {
165         if(state!=IDLE)
166         {
167                 while(state==BUSY) ;
168                 // Force finish to clean up the loader
169                 state = LOAD_FINISHED;
170                 sync();
171         }
172
173         resource = r;
174         state = BUSY;
175         sem.signal();
176 }
177
178 void ResourceManager::LoadingThread::sync()
179 {
180         State s = state;
181         bool finished = (s==LOAD_FINISHED);
182         if(s==SYNC_PENDING)
183         {
184                 Resource::AsyncLoader *ldr = resource->loader;
185                 while(!finished && ldr->needs_sync())
186                         finished = ldr->process();
187
188                 if(!finished)
189                 {
190                         state = BUSY;
191                         sem.signal();
192                         return;
193                 }
194         }
195
196         if(finished)
197         {
198                 resource->finish_loading();
199                 resource = 0;
200                 state = IDLE;
201         }
202 }
203
204 void ResourceManager::LoadingThread::terminate()
205 {
206         while(state==BUSY) ;
207         state = TERMINATING;
208         sem.signal();
209         join();
210 }
211
212 } // namespace GL
213 } // namespace Msp