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