Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLCoreFrameCache.h"
24 : #include "XLCoreDevice.h"
25 : #include "XLCoreLoop.h"
26 :
27 : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
28 :
29 64 : FrameCache::~FrameCache() { }
30 :
31 32 : bool FrameCache::init(Loop &loop, Device &dev) {
32 32 : _loop = &loop;
33 32 : _device = &dev;
34 32 : return true;
35 : }
36 :
37 32 : void FrameCache::invalidate() {
38 32 : _framebuffers.clear();
39 32 : _imageViews.clear();
40 32 : _renderPasses.clear();
41 32 : _images.clear();
42 32 : }
43 :
44 7322 : Rc<Framebuffer> FrameCache::acquireFramebuffer(const QueuePassData *data, SpanView<Rc<ImageView>> views) {
45 7322 : auto e = views.front()->getFramebufferExtent();
46 7322 : Vector<uint64_t> ids; ids.reserve(views.size() + 2);
47 7322 : ids.emplace_back(data->impl->getIndex());
48 7322 : ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
49 29288 : for (auto &it : views) {
50 21966 : ids.emplace_back(it->getIndex());
51 : }
52 :
53 7322 : auto it = _framebuffers.find(ids);
54 7322 : if (it != _framebuffers.end()) {
55 7232 : if (!it->second.framebuffers.empty()) {
56 7232 : auto fb = it->second.framebuffers.back();
57 7232 : it->second.framebuffers.pop_back();
58 7232 : return fb;
59 7232 : }
60 : }
61 :
62 90 : return _device->makeFramebuffer(data, views);
63 7322 : }
64 :
65 7322 : void FrameCache::releaseFramebuffer(Rc<Framebuffer> &&fb) {
66 7322 : auto e = fb->getFramebufferExtent();
67 7322 : Vector<uint64_t> ids; ids.reserve(fb->getViewIds().size() + 2);
68 7322 : ids.emplace_back(fb->getRenderPass()->getIndex());
69 7322 : ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
70 29288 : for (auto &it : fb->getViewIds()) {
71 21966 : ids.emplace_back(it);
72 : }
73 :
74 7322 : if (isReachable(SpanView<uint64_t>(ids))) {
75 7322 : auto it = _framebuffers.find(ids);
76 7322 : if (it == _framebuffers.end()) {
77 180 : _framebuffers.emplace(move(ids), FrameCacheFramebuffer{ Vector<Rc<Framebuffer>>{move(fb)}, e });
78 : } else {
79 7232 : it->second.framebuffers.emplace_back(move(fb));
80 : }
81 : }
82 7322 : }
83 :
84 21998 : Rc<ImageStorage> FrameCache::acquireImage(uint64_t attachment, const ImageInfoData &info, SpanView<ImageViewInfo> v) {
85 240 : auto makeImage = [&, this] {
86 80 : auto ret = _device->makeImage(info);
87 80 : ret->rearmSemaphores(*_loop);
88 80 : makeViews(ret, v);
89 80 : return ret;
90 0 : };
91 :
92 21998 : auto aIt = _attachments.find(attachment);
93 21998 : if (aIt == _attachments.end() || (info.hints & core::ImageHints::DoNotCache) != core::ImageHints::None) {
94 0 : return makeImage();
95 : }
96 :
97 21998 : if (aIt->second == nullptr) {
98 80 : aIt->second = addImage(info);
99 21918 : } else if (*aIt->second != info) {
100 0 : removeImage(*aIt->second);
101 0 : aIt->second = addImage(info);
102 : }
103 :
104 21998 : auto imageIt = _images.find(info);
105 21998 : if (imageIt != _images.end()) {
106 21998 : if (!imageIt->second.images.empty()) {
107 21918 : auto ret = move(imageIt->second.images.back());
108 21918 : imageIt->second.images.pop_back();
109 21918 : ret->rearmSemaphores(*_loop);
110 21918 : makeViews(ret, v);
111 21918 : return ret;
112 21918 : }
113 : }
114 :
115 80 : return makeImage();
116 : }
117 :
118 21982 : void FrameCache::releaseImage(Rc<ImageStorage> &&img) {
119 21982 : if (!img->isCacheable()) {
120 0 : img->cleanup();
121 0 : return;
122 : }
123 :
124 21982 : auto info = img->getInfo();
125 21982 : auto imageIt = _images.find(info);
126 21982 : if (imageIt == _images.end()) {
127 0 : log::warn("FrameCache", "releaseImage: cache miss: ", img->getInfo());
128 0 : return;
129 : }
130 :
131 21982 : imageIt->second.images.emplace_back(move(img));
132 : }
133 :
134 176 : void FrameCache::addImageView(uint64_t id) {
135 176 : _imageViews.emplace(id);
136 176 : }
137 :
138 176 : void FrameCache::removeImageView(uint64_t id) {
139 176 : auto it = _imageViews.find(id);
140 176 : if (it != _imageViews.end()) {
141 48 : _imageViews.erase(it);
142 :
143 48 : auto iit = _framebuffers.begin();
144 122 : while (iit != _framebuffers.end()) {
145 74 : if (!isReachable(SpanView<uint64_t>(iit->first))) {
146 52 : for (auto &it : iit->second.framebuffers) {
147 26 : _autorelease.emplace_back(it);
148 : }
149 26 : iit = _framebuffers.erase(iit);
150 : } else {
151 48 : ++ iit;
152 : }
153 : }
154 : }
155 176 : }
156 :
157 223 : void FrameCache::addRenderPass(uint64_t id) {
158 223 : _renderPasses.emplace(id);
159 223 : }
160 :
161 159 : void FrameCache::removeRenderPass(uint64_t id) {
162 159 : auto it = _renderPasses.find(id);
163 159 : if (it != _renderPasses.end()) {
164 0 : _renderPasses.erase(it);
165 :
166 0 : auto iit = _framebuffers.begin();
167 0 : while (iit != _framebuffers.end()) {
168 0 : if (!isReachable(SpanView<uint64_t>(iit->first))) {
169 0 : for (auto &it : iit->second.framebuffers) {
170 0 : _autorelease.emplace_back(it);
171 : }
172 0 : iit = _framebuffers.erase(iit);
173 : } else {
174 0 : ++ iit;
175 : }
176 : }
177 : }
178 159 : }
179 :
180 80 : void FrameCache::addAttachment(uint64_t id) {
181 80 : _attachments.emplace(id, nullptr);
182 80 : }
183 :
184 80 : void FrameCache::removeAttachment(uint64_t id) {
185 80 : auto it = _attachments.find(id);
186 80 : if (it == _attachments.end()) {
187 0 : return;
188 : }
189 :
190 80 : if (it->second) {
191 80 : removeImage(*it->second);
192 : }
193 80 : _attachments.erase(it);
194 : }
195 :
196 80 : void FrameCache::removeUnreachableFramebuffers() {
197 80 : auto fbsIt = _framebuffers.begin();
198 80 : while (fbsIt != _framebuffers.end()) {
199 0 : auto e = fbsIt->second.extent;
200 0 : bool found = false;
201 0 : for (auto &it : _images) {
202 0 : if (it.first.extent.width == e.width && it.first.extent.height == e.height) {
203 0 : found = true;
204 : }
205 : }
206 0 : if (!found) {
207 0 : for (auto &it : fbsIt->second.framebuffers) {
208 0 : _autorelease.emplace_back(it);
209 : }
210 0 : fbsIt = _framebuffers.erase(fbsIt);
211 : } else {
212 0 : auto fbIt = fbsIt->second.framebuffers.begin();
213 0 : while (fbIt != fbsIt->second.framebuffers.end()) {
214 0 : auto e = (*fbIt)->getFramebufferExtent();
215 0 : Vector<uint64_t> ids; ids.reserve((*fbIt)->getViewIds().size() + 2);
216 0 : ids.emplace_back((*fbIt)->getRenderPass()->getIndex());
217 0 : ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
218 0 : for (auto &it : (*fbIt)->getViewIds()) {
219 0 : ids.emplace_back(it);
220 : }
221 :
222 0 : if (isReachable(SpanView<uint64_t>(ids))) {
223 0 : _autorelease.emplace_back(*fbIt);
224 0 : fbIt = fbsIt->second.framebuffers.erase(fbIt);
225 : } else {
226 0 : ++ fbIt;
227 : }
228 0 : }
229 :
230 0 : if (fbsIt->second.framebuffers.empty()) {
231 0 : fbsIt = _framebuffers.erase(fbsIt);
232 : } else {
233 0 : ++ fbsIt;
234 : }
235 : }
236 : }
237 80 : }
238 :
239 7323 : size_t FrameCache::getFramebuffersCount() const {
240 7323 : size_t ret = 0;
241 36361 : for (auto &it : _framebuffers) {
242 29038 : ret += it.second.framebuffers.size();
243 : }
244 7323 : return ret;
245 : }
246 :
247 7323 : size_t FrameCache::getImagesCount() const {
248 7323 : size_t ret = 0;
249 36551 : for (auto &it : _images) {
250 29228 : ret += it.second.images.size();
251 : }
252 7323 : return ret;
253 : }
254 :
255 7323 : size_t FrameCache::getImageViewsCount() const {
256 7323 : return _imageViews.size();
257 : }
258 :
259 605226 : void FrameCache::clear() {
260 605226 : if (!_freezed) {
261 605226 : _autorelease.clear();
262 : }
263 605226 : }
264 :
265 0 : void FrameCache::freeze() {
266 0 : _freezed = true;
267 0 : }
268 :
269 0 : void FrameCache::unfreeze() {
270 0 : if (_freezed) {
271 0 : _autorelease.clear();
272 : }
273 0 : _freezed = false;
274 0 : }
275 :
276 7396 : bool FrameCache::isReachable(SpanView<uint64_t> ids) const {
277 7396 : auto fb = ids.front();
278 7396 : if (_renderPasses.find(fb) == _renderPasses.end()) {
279 0 : return false;
280 : }
281 :
282 7396 : ids = ids.sub(2, ids.size() - 2);
283 29506 : for (auto &it : ids) {
284 22136 : if (_imageViews.find(it) == _imageViews.end()) {
285 26 : return false;
286 : }
287 : }
288 7370 : return true;
289 : }
290 :
291 0 : bool FrameCache::isReachable(const ImageInfoData &info) const {
292 0 : auto it = _images.find(info);
293 0 : return it != _images.end();
294 : }
295 :
296 80 : const ImageInfoData *FrameCache::addImage(const ImageInfoData &info) {
297 80 : auto it = _images.find(info);
298 80 : if (it == _images.end()) {
299 80 : it = _images.emplace(info, FrameCacheImageAttachment{uint32_t(1), Vector<Rc<ImageStorage>>()}).first;
300 : } else {
301 0 : ++ it->second.refCount;
302 : }
303 80 : return &it->first;
304 : }
305 :
306 80 : void FrameCache::removeImage(const ImageInfoData &info) {
307 80 : auto it = _images.find(info);
308 80 : if (it != _images.end()) {
309 16 : if (it->second.refCount == 1) {
310 16 : for (auto &iit : it->second.images) {
311 0 : _autorelease.emplace_back(iit);
312 : }
313 16 : _images.erase(it);
314 : } else {
315 0 : -- it->second.refCount;
316 : }
317 : }
318 80 : }
319 :
320 21998 : void FrameCache::makeViews(const Rc<ImageStorage> &img, SpanView<ImageViewInfo> views) {
321 51318 : for (auto &info : views) {
322 29320 : auto v = img->getView(info);
323 29320 : if (!v) {
324 96 : auto v = _device->makeImageView(img->getImage(), info);
325 96 : addImageView(v->getIndex());
326 96 : v->setReleaseCallback([loop = Rc<Loop>(_loop), id = v->getIndex()] {
327 96 : loop->performOnGlThread([loop, id] {
328 96 : loop->getFrameCache()->removeImageView(id);
329 96 : });
330 96 : });
331 96 : img->addView(info, move(v));
332 96 : }
333 29320 : }
334 21998 : }
335 :
336 : }
|