Line data Source code
1 : /**
2 : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLResourceCache.h"
25 : #include "XLTemporaryResource.h"
26 : #include "XLCoreLoop.h"
27 : #include "XLApplication.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
30 :
31 60 : ResourceCache::~ResourceCache() { }
32 :
33 30 : bool ResourceCache::init(Application *a) {
34 30 : _application = a;
35 30 : return true;
36 : }
37 :
38 30 : void ResourceCache::initialize(const core::Loop &loop) {
39 30 : _loop = &loop;
40 30 : }
41 :
42 60 : void ResourceCache::invalidate() {
43 75 : for (auto &it : _temporaries) {
44 15 : it.second->invalidate();
45 : }
46 60 : _images.clear();
47 60 : _temporaries.clear();
48 60 : _resources.clear();
49 60 : _loop = nullptr;
50 60 : }
51 :
52 6890 : void ResourceCache::update(const UpdateTime &time) {
53 6890 : auto it = _temporaries.begin();
54 8015 : while (it != _temporaries.end()) {
55 1125 : if (it->second->getUsersCount() > 0 && !it->second->isRequested()) {
56 15 : compileResource(it->second);
57 15 : ++ it;
58 1110 : } else if (it->second->isDeprecated(time)) {
59 15 : if (clearResource(it->second)) {
60 0 : it = _temporaries.erase(it);
61 : } else {
62 15 : ++ it;
63 : }
64 : } else {
65 1095 : ++ it;
66 : }
67 : }
68 6890 : }
69 :
70 60 : void ResourceCache::addImage(StringView name, const Rc<core::ImageObject> &img) {
71 60 : auto it = _images.emplace(name, core::ImageData()).first;
72 60 : static_cast<core::ImageInfoData &>(it->second) = img->getInfo();
73 60 : it->second.image = img;
74 60 : }
75 :
76 15 : void ResourceCache::addResource(const Rc<core::Resource> &req) {
77 15 : _resources.emplace(req->getName(), req);
78 15 : }
79 :
80 15 : void ResourceCache::removeResource(StringView requestName) {
81 15 : _resources.erase(requestName);
82 15 : }
83 :
84 34174 : Rc<Texture> ResourceCache::acquireTexture(StringView str) const {
85 34174 : auto iit = _images.find(str);
86 34174 : if (iit != _images.end()) {
87 68156 : return Rc<Texture>::create(&iit->second);
88 : }
89 :
90 96 : for (auto &it : _temporaries) {
91 6 : if (auto tex = it.second->acquireTexture(str)) {
92 6 : return tex;
93 6 : }
94 : }
95 :
96 90 : for (auto &it : _resources) {
97 90 : if (auto v = it.second->getImage(str)) {
98 90 : return Rc<Texture>::create(v, it.second);
99 : }
100 : }
101 :
102 0 : log::error("ResourceCache", "Texture not found: ", str);
103 0 : return nullptr;
104 : }
105 :
106 0 : Rc<MeshIndex> ResourceCache::acquireMeshIndex(StringView str) const {
107 0 : for (auto &it : _temporaries) {
108 0 : if (auto mesh = it.second->acquireMeshIndex(str)) {
109 0 : return mesh;
110 0 : }
111 : }
112 :
113 0 : for (auto &it : _resources) {
114 0 : if (auto v = it.second->getBuffer(str)) {
115 0 : return Rc<MeshIndex>::create(v, it.second);
116 : }
117 : }
118 :
119 0 : log::error("ResourceCache", "MeshIndex not found: ", str);
120 0 : return nullptr;
121 : }
122 :
123 30 : const core::ImageData *ResourceCache::getEmptyImage() const {
124 30 : auto iit = _images.find(StringView(core::EmptyTextureName));
125 30 : if (iit != _images.end()) {
126 30 : return &iit->second;
127 : }
128 0 : return nullptr;
129 : }
130 :
131 30 : const core::ImageData *ResourceCache::getSolidImage() const {
132 30 : auto iit = _images.find(StringView(core::SolidTextureName));
133 30 : if (iit != _images.end()) {
134 30 : return &iit->second;
135 : }
136 0 : return nullptr;
137 : }
138 :
139 0 : Rc<Texture> ResourceCache::addExternalImageByRef(StringView key, core::ImageInfo &&info, BytesView data, TimeInterval ival, TemporaryResourceFlags flags) {
140 0 : auto it = _temporaries.find(key);
141 0 : if (it != _temporaries.end()) {
142 0 : if (auto tex = it->second->acquireTexture(key)) {
143 0 : return tex;
144 0 : }
145 0 : log::error("ResourceCache", "Resource '", key, "' already exists, but no texture '", key, "' found");
146 0 : return nullptr;
147 : }
148 :
149 0 : core::Resource::Builder builder(key);
150 0 : if (auto d = builder.addImageByRef(key, move(info), data)) {
151 0 : if (auto tmp = addTemporaryResource(Rc<core::Resource>::create(move(builder)), ival, flags)) {
152 0 : return Rc<Texture>::create(d, tmp);
153 0 : }
154 : }
155 0 : return nullptr;
156 0 : }
157 :
158 15 : Rc<Texture> ResourceCache::addExternalImage(StringView key, core::ImageInfo &&info, FilePath data, TimeInterval ival, TemporaryResourceFlags flags) {
159 15 : auto it = _temporaries.find(key);
160 15 : if (it != _temporaries.end()) {
161 0 : if (auto tex = it->second->acquireTexture(key)) {
162 0 : return tex;
163 0 : }
164 0 : log::error("ResourceCache", "Resource '", key, "' already exists, but no texture '", key, "' found");
165 0 : return nullptr;
166 : }
167 :
168 15 : core::Resource::Builder builder(key);
169 15 : if (auto d = builder.addImage(key, move(info), data)) {
170 30 : if (auto tmp = addTemporaryResource(Rc<core::Resource>::create(move(builder)), ival, flags)) {
171 15 : return Rc<Texture>::create(d, tmp);
172 15 : }
173 : }
174 0 : return nullptr;
175 15 : }
176 :
177 0 : Rc<Texture> ResourceCache::addExternalImage(StringView key, core::ImageInfo &&info, BytesView data, TimeInterval ival, TemporaryResourceFlags flags) {
178 0 : auto it = _temporaries.find(key);
179 0 : if (it != _temporaries.end()) {
180 0 : if (auto tex = it->second->acquireTexture(key)) {
181 0 : return tex;
182 0 : }
183 0 : log::error("ResourceCache", "Resource '", key, "' already exists, but no texture '", key, "' found");
184 0 : return nullptr;
185 : }
186 :
187 0 : core::Resource::Builder builder(key);
188 0 : if (auto d = builder.addImage(key, move(info), data)) {
189 0 : if (auto tmp = addTemporaryResource(Rc<core::Resource>::create(move(builder)), ival, flags)) {
190 0 : return Rc<Texture>::create(d, tmp);
191 0 : }
192 : }
193 :
194 0 : return nullptr;
195 0 : }
196 :
197 0 : Rc<Texture> ResourceCache::addExternalImage(StringView key, core::ImageInfo &&info,
198 : const memory::function<void(uint8_t *, uint64_t, const core::ImageData::DataCallback &)> &cb,
199 : TimeInterval ival, TemporaryResourceFlags flags) {
200 0 : auto it = _temporaries.find(key);
201 0 : if (it != _temporaries.end()) {
202 0 : if (auto tex = it->second->acquireTexture(key)) {
203 0 : return tex;
204 0 : }
205 0 : log::error("ResourceCache", "Resource '", key, "' already exists, but no texture '", key, "' found");
206 0 : return nullptr;
207 : }
208 :
209 0 : core::Resource::Builder builder(key);
210 0 : if (auto d = builder.addImage(key, move(info), cb)) {
211 0 : if (auto tmp = addTemporaryResource(Rc<core::Resource>::create(move(builder)), ival, flags)) {
212 0 : return Rc<Texture>::create(d, tmp);
213 0 : }
214 : }
215 0 : return nullptr;
216 0 : }
217 :
218 15 : Rc<TemporaryResource> ResourceCache::addTemporaryResource(Rc<core::Resource> &&res, TimeInterval ival, TemporaryResourceFlags flags) {
219 15 : auto tmp = Rc<TemporaryResource>::create(move(res), ival, flags);
220 15 : auto it = _temporaries.find(tmp->getName());
221 15 : if (it != _temporaries.end()) {
222 0 : _temporaries.erase(it);
223 : }
224 15 : it = _temporaries.emplace(tmp->getName(), move(tmp)).first;
225 :
226 15 : if ((flags & TemporaryResourceFlags::CompileWhenAdded) != TemporaryResourceFlags::None) {
227 0 : compileResource(it->second);
228 : }
229 30 : return it->second;
230 15 : }
231 :
232 30 : Rc<TemporaryResource> ResourceCache::getTemporaryResource(StringView str) const {
233 30 : auto it = _temporaries.find(str);
234 30 : if (it != _temporaries.end()) {
235 15 : return it->second;
236 : }
237 15 : return nullptr;
238 : }
239 :
240 0 : bool ResourceCache::hasTemporaryResource(StringView str) const {
241 0 : auto it = _temporaries.find(str);
242 0 : if (it != _temporaries.end()) {
243 0 : return true;
244 : }
245 0 : return false;
246 : }
247 :
248 0 : void ResourceCache::removeTemporaryResource(StringView str) {
249 0 : auto it = _temporaries.find(str);
250 0 : if (it != _temporaries.end()) {
251 0 : it->second->clear();
252 0 : _temporaries.erase(it);
253 : }
254 0 : }
255 :
256 15 : void ResourceCache::compileResource(TemporaryResource *res) {
257 15 : if (_loop) {
258 15 : res->setRequested(true);
259 30 : _loop->compileResource(Rc<core::Resource>(res->getResource()),
260 30 : [res = Rc<TemporaryResource>(res), guard = Rc<ResourceCache>(this)] (bool success) mutable {
261 15 : guard->getApplication()->performOnMainThread([guard, res = move(res), success] {
262 15 : res->setLoaded(success);
263 15 : guard->getApplication()->wakeup();
264 15 : }, nullptr, false);
265 15 : });
266 : }
267 15 : }
268 :
269 15 : bool ResourceCache::clearResource(TemporaryResource *res) {
270 15 : return res->clear();
271 : }
272 :
273 : }
|