]> git.tdb.fi Git - libs/gl.git/blob - source/resourcemanager.h
Make ResourceManager thread-safe
[libs/gl.git] / source / resourcemanager.h
1 #ifndef MSP_GL_RESOURCEMANAGER_H_
2 #define MSP_GL_RESOURCEMANAGER_H_
3
4 #include <msp/core/inttypes.h>
5 #include <msp/core/mutex.h>
6 #include <msp/core/semaphore.h>
7 #include <msp/core/thread.h>
8 #include <msp/datafile/collection.h>
9 #include "resource.h"
10
11 namespace Msp {
12 namespace GL {
13
14 class ResourceWatcher;
15
16 class resource_load_error: public std::runtime_error
17 {
18 public:
19         resource_load_error(const std::string &, const std::string &);
20         resource_load_error(const std::string &, const std::exception &);
21         virtual ~resource_load_error() throw() { }
22 };
23
24
25 class ResourceManager
26 {
27 public:
28         enum LoadingPolicy
29         {
30                 LOAD_IMMEDIATELY,
31                 LOAD_ON_DEMAND,
32                 LOAD_MANUALLY
33         };
34
35         struct ResourceLocation
36         {
37                 DataFile::Collection *collection;
38                 std::string name;
39
40                 ResourceLocation();
41                 ResourceLocation(DataFile::Collection &, const std::string &);
42         };
43
44 private:
45         struct ManagedResource
46         {
47                 enum State
48                 {
49                         NOT_LOADED,
50                         LOAD_QUEUED,
51                         LOADING,
52                         LOAD_FINISHED,
53                         LOADED,
54                         LOAD_ERROR
55                 };
56
57                 Resource *resource;
58                 ResourceLocation location;
59                 bool load_priority;
60                 IO::Seekable *io;
61                 Resource::AsyncLoader *loader;
62                 State state;
63                 unsigned last_used;
64                 UInt64 data_size;
65                 std::vector<ResourceWatcher *> watchers;
66
67                 ManagedResource(Resource &);
68
69                 void start_loading();
70                 bool process(bool);
71                 void finish_loading(bool);
72                 void finish_loading();
73                 void unload();
74
75                 void add_watcher(ResourceWatcher &);
76                 void remove_watcher(ResourceWatcher &);
77         };
78
79         typedef std::list<ManagedResource *> LoadQueue;
80
81         class LoadingThread: public Thread
82         {
83         private:
84                 Semaphore sem;
85                 Mutex queue_mutex;
86                 LoadQueue async_queue;
87                 LoadQueue sync_queue;
88                 unsigned capacity;
89                 unsigned size;
90                 std::list<resource_load_error> error_queue;
91                 volatile bool done;
92
93         public:
94                 LoadingThread();
95
96         private:
97                 virtual void main();
98
99                 ManagedResource *front(LoadQueue &);
100
101         public:
102                 void add_resource(ManagedResource &);
103                 void remove_resource(ManagedResource &);
104         private:
105                 bool try_remove_resource(ManagedResource &);
106         public:
107                 bool sync();
108                 bool needs_work() const { return size<capacity; }
109
110                 void terminate();
111         };
112
113         typedef std::map<const Resource *, ManagedResource> ResourceMap;
114
115         LoadingPolicy policy;
116         bool async_loads;
117         mutable Mutex map_mutex;
118         ResourceMap resources;
119         LoadQueue queue;
120         UInt64 size_limit;
121         unsigned frame;
122         unsigned min_retain_frames;
123         unsigned max_retain_frames;
124         unsigned next_unload;
125         LoadingThread thread;
126
127 public:
128         ResourceManager();
129         ~ResourceManager();
130
131         void set_loading_policy(LoadingPolicy);
132         void set_async_loads(bool);
133         void set_size_limit(UInt64);
134         void set_min_retain_frames(unsigned);
135         void set_max_retain_frames(unsigned);
136
137         void add_resource(Resource &);
138 private:
139         const ManagedResource &get_managed_resource(const Resource &) const;
140         ManagedResource &get_managed_resource(const Resource &);
141 public:
142         void *get_data_for_resource(const Resource &r) { return &get_managed_resource(r); }
143         void set_resource_location(Resource &, DataFile::Collection &, const std::string &);
144         void set_resource_location(Resource &, const ResourceLocation &);
145         const ResourceLocation *get_resource_location(const Resource &) const;
146         void load_resource(Resource &);
147         bool is_resource_loaded(const Resource &) const;
148         void resource_used(const Resource &);
149         void remove_resource(Resource &);
150
151         void watch_resource(const Resource &, ResourceWatcher &);
152         void unwatch_resource(const Resource &, ResourceWatcher &);
153
154         void tick();
155 private:
156         void dispatch_work();
157         void unload_by_age();
158         void unload_by_size();
159         UInt64 get_total_data_size_() const;
160 public:
161         UInt64 get_total_data_size() const;
162
163 private:
164         static bool age_order(ManagedResource *, ManagedResource *);
165 };
166
167 } // namespace GL
168 } // namespace Msp
169
170 #endif