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 "XLCoreResource.h"
25 : #include "SPBitmap.h"
26 :
27 : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
28 :
29 : struct Resource::ResourceData : memory::AllocPool {
30 : HashTable<BufferData *> buffers;
31 : HashTable<ImageData *> images;
32 :
33 : const Queue *owner = nullptr;
34 : bool compiled = false;
35 : StringView key;
36 : memory::pool_t *pool = nullptr;
37 :
38 144 : void clear() {
39 144 : compiled = false;
40 944 : for (auto &it : buffers) {
41 800 : it->buffer = nullptr;
42 : }
43 448 : for (auto &it : images) {
44 304 : it->image = nullptr;
45 : }
46 144 : }
47 : };
48 :
49 112 : static void Resource_loadImageDirect(uint8_t *glBuffer, uint64_t expectedSize, BytesView encodedImageData, const bitmap::ImageInfo &imageInfo) {
50 : struct WriteData {
51 : uint8_t *buffer;
52 : uint32_t offset;
53 : uint64_t expectedSize;
54 : } data;
55 :
56 112 : data.buffer = glBuffer;
57 112 : data.offset = 0;
58 112 : data.expectedSize = expectedSize;
59 :
60 112 : bitmap::BitmapWriter w;
61 112 : w.target = &data;
62 :
63 112 : w.getStride = nullptr;
64 112 : w.push = [] (void *ptr, const uint8_t *data, uint32_t size) {
65 0 : auto writeData = ((WriteData *)ptr);
66 0 : memcpy(writeData->buffer + writeData->offset, data, size);
67 0 : writeData->offset += size;
68 112 : };
69 224 : w.resize = [] (void *ptr, uint32_t size) {
70 112 : auto writeData = ((WriteData *)ptr);
71 112 : if (size > writeData->expectedSize) {
72 0 : abort();
73 : }
74 112 : };
75 42416 : w.getData = [] (void *ptr, uint32_t location) {
76 42304 : auto writeData = ((WriteData *)ptr);
77 42304 : return writeData->buffer + location;
78 112 : };
79 112 : w.assign = [] (void *ptr, const uint8_t *data, uint32_t size) {
80 0 : auto writeData = ((WriteData *)ptr);
81 0 : memcpy(writeData->buffer, data, size);
82 0 : writeData->offset = size;
83 112 : };
84 112 : w.clear = [] (void *ptr) { };
85 :
86 112 : imageInfo.format->load(encodedImageData.data(), encodedImageData.size(), w);
87 112 : }
88 :
89 192 : static void Resource_loadImageConverted(StringView path, uint8_t *glBuffer, BytesView encodedImageData, const bitmap::ImageInfo &imageInfo, ImageFormat fmt) {
90 192 : Bitmap bmp(encodedImageData);
91 :
92 192 : switch (fmt) {
93 48 : case ImageFormat::R8G8B8A8_SRGB:
94 : case ImageFormat::R8G8B8A8_UNORM:
95 : case ImageFormat::R8G8B8A8_UINT:
96 48 : bmp.convertWithTarget(glBuffer, bitmap::PixelFormat::RGBA8888);
97 48 : break;
98 48 : case ImageFormat::R8G8B8_SRGB:
99 : case ImageFormat::R8G8B8_UNORM:
100 : case ImageFormat::R8G8B8_UINT:
101 48 : bmp.convertWithTarget(glBuffer, bitmap::PixelFormat::RGB888);
102 48 : break;
103 48 : case ImageFormat::R8G8_SRGB:
104 : case ImageFormat::R8G8_UNORM:
105 : case ImageFormat::R8G8_UINT:
106 48 : bmp.convertWithTarget(glBuffer, bitmap::PixelFormat::IA88);
107 48 : break;
108 48 : case ImageFormat::R8_SRGB:
109 : case ImageFormat::R8_UNORM:
110 : case ImageFormat::R8_UINT:
111 48 : if (bmp.alpha() == bitmap::AlphaFormat::Opaque) {
112 16 : bmp.convertWithTarget(glBuffer, bitmap::PixelFormat::I8);
113 : } else {
114 32 : bmp.convertWithTarget(glBuffer, bitmap::PixelFormat::A8);
115 : }
116 48 : break;
117 0 : default:
118 0 : log::error("Resource", "loadImageConverted: ", path, ": Invalid image format: ", getImageFormatName(fmt));
119 0 : break;
120 : }
121 192 : }
122 :
123 256 : static void Resource_loadImageDefault(StringView path, BytesView encodedImageData, ImageFormat fmt, const ImageData::DataCallback &dcb) {
124 256 : Bitmap bmp(encodedImageData);
125 :
126 256 : bool availableFormat = true;
127 256 : switch (fmt) {
128 64 : case ImageFormat::R8G8B8A8_SRGB:
129 : case ImageFormat::R8G8B8A8_UNORM:
130 : case ImageFormat::R8G8B8A8_UINT:
131 64 : bmp.convert(bitmap::PixelFormat::RGBA8888);
132 64 : break;
133 64 : case ImageFormat::R8G8B8_SRGB:
134 : case ImageFormat::R8G8B8_UNORM:
135 : case ImageFormat::R8G8B8_UINT:
136 64 : bmp.convert(bitmap::PixelFormat::RGB888);
137 64 : break;
138 64 : case ImageFormat::R8G8_SRGB:
139 : case ImageFormat::R8G8_UNORM:
140 : case ImageFormat::R8G8_UINT:
141 64 : bmp.convert(bitmap::PixelFormat::IA88);
142 64 : break;
143 64 : case ImageFormat::R8_SRGB:
144 : case ImageFormat::R8_UNORM:
145 : case ImageFormat::R8_UINT:
146 64 : bmp.convert(bitmap::PixelFormat::A8);
147 64 : break;
148 0 : default:
149 0 : availableFormat = false;
150 0 : log::error("Resource", "loadImageDefault: ", path, ": Invalid image format: ", getImageFormatName(fmt));
151 0 : break;
152 : }
153 :
154 256 : if (availableFormat) {
155 256 : dcb(BytesView(bmp.dataPtr(), bmp.data().size()));
156 : } else {
157 0 : dcb(BytesView());
158 : }
159 256 : }
160 :
161 560 : void Resource::loadImageMemoryData(uint8_t *ptr, uint64_t expectedSize, BytesView data, ImageFormat fmt, const ImageData::DataCallback &dcb) {
162 560 : bitmap::ImageInfo info;
163 560 : if (!bitmap::getImageInfo(data, info)) {
164 0 : log::error("Resource", "loadImageMmmoryData: fail to read image info");
165 : } else {
166 560 : if (ptr) {
167 : // check if we can load directly into GL memory
168 304 : switch (info.color) {
169 112 : case bitmap::PixelFormat::RGBA8888:
170 : switch (fmt) {
171 64 : case ImageFormat::R8G8B8A8_SRGB:
172 : case ImageFormat::R8G8B8A8_UNORM:
173 : case ImageFormat::R8G8B8A8_UINT:
174 64 : Resource_loadImageDirect(ptr, expectedSize, data, info);
175 64 : break;
176 48 : default:
177 48 : Resource_loadImageConverted(StringView(), ptr, data, info, fmt);
178 48 : break;
179 : }
180 112 : break;
181 64 : case bitmap::PixelFormat::RGB888:
182 : switch (fmt) {
183 16 : case ImageFormat::R8G8B8_SRGB:
184 : case ImageFormat::R8G8B8_UNORM:
185 : case ImageFormat::R8G8B8_UINT:
186 16 : Resource_loadImageDirect(ptr, expectedSize, data, info);
187 16 : break;
188 48 : default:
189 48 : Resource_loadImageConverted(StringView(), ptr, data, info, fmt);
190 48 : break;
191 : }
192 64 : break;
193 64 : case bitmap::PixelFormat::IA88:
194 : switch (fmt) {
195 16 : case ImageFormat::R8G8_SRGB:
196 : case ImageFormat::R8G8_UNORM:
197 : case ImageFormat::R8G8_UINT:
198 16 : Resource_loadImageDirect(ptr, expectedSize, data, info);
199 16 : break;
200 48 : default:
201 48 : Resource_loadImageConverted(StringView(), ptr, data, info, fmt);
202 48 : break;
203 : }
204 64 : break;
205 64 : case bitmap::PixelFormat::I8:
206 : case bitmap::PixelFormat::A8:
207 : switch (fmt) {
208 16 : case ImageFormat::R8_SRGB:
209 : case ImageFormat::R8_UNORM:
210 : case ImageFormat::R8_UINT:
211 16 : Resource_loadImageDirect(ptr, expectedSize, data, info);
212 16 : break;
213 48 : default:
214 48 : Resource_loadImageConverted(StringView(), ptr, data, info, fmt);
215 48 : break;
216 : }
217 64 : break;
218 0 : default:
219 0 : log::error("Resource", "loadImageMemoryData: Unknown format");
220 0 : dcb(BytesView());
221 0 : break;
222 : }
223 : } else {
224 : // use data callback
225 256 : Resource_loadImageDefault(StringView(), data, fmt, dcb);
226 : }
227 : }
228 560 : }
229 :
230 48 : void Resource::loadImageFileData(uint8_t *ptr, uint64_t expectedSize, StringView path, ImageFormat fmt, const ImageData::DataCallback &dcb) {
231 48 : auto p = memory::pool::create(memory::pool::acquire());
232 48 : memory::pool::push(p);
233 48 : auto f = filesystem::openForReading(path);
234 48 : if (f) {
235 48 : auto fsize = f.size();
236 48 : auto mem = (uint8_t *)memory::pool::palloc(p, fsize);
237 48 : f.seek(0, io::Seek::Set);
238 48 : f.read(mem, fsize);
239 48 : f.close();
240 :
241 48 : loadImageMemoryData(ptr, expectedSize, BytesView(mem, fsize), fmt, dcb);
242 : } else {
243 0 : log::error("Resource", "loadImageFileData: ", path, ": fail to load file");
244 0 : dcb(BytesView());
245 : }
246 48 : memory::pool::pop();
247 48 : memory::pool::destroy(p);
248 48 : };
249 :
250 80 : Resource::Resource() { }
251 :
252 160 : Resource::~Resource() {
253 80 : if (_data) {
254 80 : _data->clear();
255 80 : auto p = _data->pool;
256 80 : memory::pool::destroy(p);
257 80 : _data = nullptr;
258 : }
259 160 : }
260 :
261 80 : bool Resource::init(Builder && buf) {
262 80 : _data = buf._data;
263 80 : buf._data = nullptr;
264 272 : for (auto &it : _data->images) {
265 192 : it->resource = this;
266 : }
267 512 : for (auto &it : _data->buffers) {
268 432 : it->resource = this;
269 : }
270 80 : return true;
271 : }
272 :
273 64 : void Resource::clear() {
274 64 : _data->clear();
275 64 : }
276 :
277 32 : bool Resource::isCompiled() const {
278 32 : return _data->compiled;
279 : }
280 :
281 64 : void Resource::setCompiled(bool value) {
282 64 : _data->compiled = value;
283 64 : }
284 :
285 32 : const Queue *Resource::getOwner() const {
286 32 : return _data->owner;
287 : }
288 :
289 48 : void Resource::setOwner(const Queue *q) {
290 48 : _data->owner = q;
291 48 : }
292 :
293 96 : const HashTable<BufferData *> &Resource::getBuffers() const {
294 96 : return _data->buffers;
295 : }
296 :
297 96 : const HashTable<ImageData *> &Resource::getImages() const {
298 96 : return _data->images;
299 : }
300 :
301 16 : const BufferData *Resource::getBuffer(StringView key) const {
302 16 : return _data->buffers.get(key);
303 : }
304 :
305 102 : const ImageData *Resource::getImage(StringView key) const {
306 102 : return _data->images.get(key);
307 : }
308 :
309 112 : StringView Resource::getName() const {
310 112 : return _data->key;
311 : }
312 :
313 16 : memory::pool_t *Resource::getPool() const {
314 16 : return _data->pool;
315 : }
316 :
317 :
318 : template <typename T>
319 2256 : static T * Resource_conditionalInsert(HashTable<T *> &vec, StringView key, const Callback<T *()> &cb, memory::pool_t *pool) {
320 2256 : auto it = vec.find(key);
321 2256 : if (it == vec.end()) {
322 1952 : T *obj = nullptr;
323 5856 : perform([&] {
324 1952 : obj = cb();
325 : }, pool);
326 1952 : if (obj) {
327 1952 : return *vec.emplace(obj).first;
328 : }
329 : }
330 304 : return nullptr;
331 : }
332 :
333 : template <typename T>
334 : static T * Resource_conditionalInsert(memory::vector<T *> &vec, StringView key, const Callback<T *()> &cb, memory::pool_t *pool) {
335 : T *obj = nullptr;
336 : perform([&] {
337 : obj = cb();
338 : }, pool);
339 : if (obj) {
340 : return vec.emplace_back(obj);
341 : }
342 : return nullptr;
343 : }
344 :
345 0 : static void Resource_loadFileData(uint8_t *ptr, uint64_t size, StringView path, const BufferData::DataCallback &dcb) {
346 0 : auto p = memory::pool::create(memory::pool::acquire());
347 0 : memory::pool::push(p);
348 0 : auto f = filesystem::openForReading(path);
349 0 : if (f) {
350 0 : uint64_t fsize = f.size();
351 0 : f.seek(0, io::Seek::Set);
352 0 : if (ptr) {
353 0 : f.read(ptr, std::min(fsize, size));
354 0 : f.close();
355 : } else {
356 0 : auto mem = (uint8_t *)memory::pool::palloc(p, fsize);
357 0 : f.read(mem, fsize);
358 0 : f.close();
359 0 : dcb(BytesView(mem, fsize));
360 : }
361 : } else {
362 0 : dcb(BytesView());
363 : }
364 0 : memory::pool::pop();
365 0 : memory::pool::destroy(p);
366 0 : };
367 :
368 224 : Resource::Builder::Builder(StringView name) {
369 224 : auto p = memory::pool::create((memory::pool_t *)nullptr);
370 224 : memory::pool::push(p);
371 224 : _data = new (p) ResourceData;
372 224 : _data->pool = p;
373 224 : _data->key = name.pdup(p);
374 224 : memory::pool::pop();
375 224 : }
376 :
377 224 : Resource::Builder::~Builder() {
378 224 : if (_data) {
379 144 : auto p = _data->pool;
380 144 : memory::pool::destroy(p);
381 144 : _data = nullptr;
382 : }
383 224 : }
384 :
385 64 : const BufferData *Resource::Builder::addBufferByRef(StringView key, BufferInfo &&info, BytesView data, Rc<DataAtlas> &&atlas, AccessType access) {
386 64 : if (!_data) {
387 0 : log::error("Resource", "Fail to add buffer: ", key, ", not initialized");
388 0 : return nullptr;
389 : }
390 :
391 64 : auto p = Resource_conditionalInsert<BufferData>(_data->buffers, key, [&, this] () -> BufferData * {
392 32 : auto buf = new (_data->pool) BufferData();
393 32 : static_cast<BufferInfo &>(*buf) = move(info);
394 32 : buf->key = key.pdup(_data->pool);
395 32 : buf->data = data;
396 32 : buf->size = data.size();
397 32 : buf->atlas = move(atlas);
398 32 : buf->targetAccess = access;
399 32 : return buf;
400 64 : }, _data->pool);
401 64 : if (!p) {
402 32 : log::error("Resource", _data->key, ": Buffer already added: ", key);
403 32 : return nullptr;
404 : }
405 32 : return p;
406 : }
407 64 : const BufferData *Resource::Builder::addBuffer(StringView key, BufferInfo &&info, FilePath path, Rc<DataAtlas> &&atlas, AccessType access) {
408 64 : if (!_data) {
409 0 : log::error("Resource", "Fail to add buffer: ", key, ", not initialized");
410 0 : return nullptr;
411 : }
412 :
413 64 : String npath;
414 64 : if (filesystem::exists(path.get())) {
415 64 : npath = path.get().str<Interface>();
416 0 : } else if (!filepath::isAbsolute(path.get())) {
417 0 : npath = filesystem::currentDir<Interface>(path.get());
418 0 : if (!filesystem::exists(npath)) {
419 0 : npath.clear();
420 : }
421 : }
422 :
423 64 : if (npath.empty()) {
424 0 : log::error("Resource", "Fail to add buffer: ", key, ", file not found: ", path.get());
425 0 : return nullptr;
426 : }
427 :
428 64 : auto p = Resource_conditionalInsert<BufferData>(_data->buffers, key, [&, this] () -> BufferData * {
429 32 : auto fpath = StringView(npath).pdup(_data->pool);
430 32 : auto buf = new (_data->pool) BufferData;
431 32 : static_cast<BufferInfo &>(*buf) = move(info);
432 32 : buf->key = key.pdup(_data->pool);
433 0 : buf->memCallback = [fpath] (uint8_t *ptr, uint64_t size, const BufferData::DataCallback &dcb) {
434 0 : Resource_loadFileData(ptr, size, fpath, dcb);
435 32 : };
436 32 : filesystem::Stat stat;
437 32 : if (filesystem::stat(path.get(), stat)) {
438 32 : buf->size = stat.size;
439 : }
440 32 : buf->atlas = move(atlas);
441 32 : buf->targetAccess = access;
442 32 : return buf;
443 64 : }, _data->pool);
444 64 : if (!p) {
445 32 : log::error("Resource", _data->key, ": Buffer already added: ", key);
446 32 : return nullptr;
447 : }
448 32 : return p;
449 64 : }
450 :
451 64 : const BufferData *Resource::Builder::addBuffer(StringView key, BufferInfo &&info, BytesView data, Rc<DataAtlas> &&atlas, AccessType access) {
452 64 : if (!_data) {
453 0 : log::error("Resource", "Fail to add buffer: ", key, ", not initialized");
454 0 : return nullptr;
455 : }
456 :
457 64 : auto p = Resource_conditionalInsert<BufferData>(_data->buffers, key, [&, this] () -> BufferData * {
458 32 : auto buf = new (_data->pool) BufferData();
459 32 : static_cast<BufferInfo &>(*buf) = move(info);
460 32 : buf->key = key.pdup(_data->pool);
461 32 : buf->data = data.pdup(_data->pool);
462 32 : buf->size = data.size();
463 32 : buf->atlas = move(atlas);
464 32 : buf->targetAccess = access;
465 32 : return buf;
466 64 : }, _data->pool);
467 64 : if (!p) {
468 32 : log::error("Resource", _data->key, ": Buffer already added: ", key);
469 32 : return nullptr;
470 : }
471 32 : return p;
472 : }
473 368 : const BufferData *Resource::Builder::addBuffer(StringView key, BufferInfo &&info,
474 : const memory::function<void(uint8_t *, uint64_t, const BufferData::DataCallback &)> &cb, Rc<DataAtlas> &&atlas, AccessType access) {
475 368 : if (!_data) {
476 0 : log::error("Resource", "Fail to add buffer: ", key, ", not initialized");
477 0 : return nullptr;
478 : }
479 :
480 368 : auto p = Resource_conditionalInsert<BufferData>(_data->buffers, key, [&, this] () -> BufferData * {
481 336 : auto buf = new (_data->pool) BufferData;
482 336 : static_cast<BufferInfo &>(*buf) = move(info);
483 336 : buf->key = key.pdup(_data->pool);
484 336 : buf->memCallback = cb;
485 336 : buf->atlas = move(atlas);
486 336 : buf->targetAccess = access;
487 336 : return buf;
488 368 : }, _data->pool);
489 368 : if (!p) {
490 32 : log::error("Resource", _data->key, ": Buffer already added: ", key);
491 32 : return nullptr;
492 : }
493 336 : return p;
494 : }
495 :
496 64 : const ImageData *Resource::Builder::addImage(StringView key, ImageInfo &&img, BytesView data, AttachmentLayout layout, AccessType access) {
497 64 : if (!_data) {
498 0 : log::error("Resource", "Fail to add image: ", key, ", not initialized");
499 0 : return nullptr;
500 : }
501 :
502 64 : auto p = Resource_conditionalInsert<ImageData>(_data->images, key, [&, this] () -> ImageData * {
503 32 : auto buf = new (_data->pool) ImageData;
504 32 : static_cast<ImageInfo &>(*buf) = move(img);
505 32 : buf->key = key.pdup(_data->pool);
506 32 : buf->data = data.pdup(_data->pool);
507 32 : buf->targetLayout = layout;
508 32 : buf->targetAccess = access;
509 32 : return buf;
510 64 : }, _data->pool);
511 64 : if (!p) {
512 32 : log::error("Resource", _data->key, ": Image already added: ", key);
513 32 : return nullptr;
514 : }
515 32 : return p;
516 : }
517 128 : const ImageData *Resource::Builder::addImage(StringView key, ImageInfo &&img, FilePath path, AttachmentLayout layout, AccessType access) {
518 128 : if (!_data) {
519 0 : log::error("Resource", "Fail to add image: ", key, ", not initialized");
520 0 : return nullptr;
521 : }
522 :
523 128 : String npath;
524 128 : if (filesystem::exists(path.get())) {
525 64 : npath = path.get().str<Interface>();
526 64 : } else if (!filepath::isAbsolute(path.get())) {
527 64 : npath = filesystem::currentDir<Interface>(path.get());
528 64 : if (!filesystem::exists(npath)) {
529 0 : npath.clear();
530 : }
531 : }
532 :
533 128 : if (npath.empty()) {
534 0 : log::error("Resource", "Fail to add image: ", key, ", file not found: ", path.get());
535 0 : return nullptr;
536 : }
537 :
538 128 : Extent3 extent;
539 128 : extent.depth = 1;
540 128 : if (!bitmap::getImageSize(StringView(npath), extent.width, extent.height)) {
541 0 : return nullptr;
542 : }
543 :
544 128 : auto p = Resource_conditionalInsert<ImageData>(_data->images, key, [&, this] () -> ImageData * {
545 96 : auto fpath = StringView(npath).pdup(_data->pool);
546 96 : auto buf = new (_data->pool) ImageData;
547 96 : static_cast<ImageInfo &>(*buf) = move(img);
548 96 : buf->key = key.pdup(_data->pool);
549 144 : buf->memCallback = [fpath, format = img.format] (uint8_t *ptr, uint64_t size, const ImageData::DataCallback &dcb) {
550 48 : Resource::loadImageFileData(ptr, size, fpath, format, dcb);
551 96 : };
552 96 : buf->extent = extent;
553 96 : buf->targetLayout = layout;
554 96 : buf->targetAccess = access;
555 96 : return buf;
556 128 : }, _data->pool);
557 128 : if (!p) {
558 32 : log::error("Resource", _data->key, ": Image already added: ", key);
559 32 : return nullptr;
560 : }
561 96 : return p;
562 128 : }
563 64 : const ImageData *Resource::Builder::addImageByRef(StringView key, ImageInfo &&img, BytesView data, AttachmentLayout layout, AccessType access) {
564 64 : if (!_data) {
565 0 : log::error("Resource", "Fail to add image: ", key, ", not initialized");
566 0 : return nullptr;
567 : }
568 :
569 64 : auto p = Resource_conditionalInsert<ImageData>(_data->images, key, [&, this] () -> ImageData * {
570 32 : auto buf = new (_data->pool) ImageData;
571 32 : static_cast<ImageInfo &>(*buf) = move(img);
572 32 : buf->key = key.pdup(_data->pool);
573 32 : buf->data = data;
574 32 : buf->targetLayout = layout;
575 32 : buf->targetAccess = access;
576 32 : return buf;
577 64 : }, _data->pool);
578 64 : if (!p) {
579 32 : log::error("Resource", _data->key, ": Image already added: ", key);
580 32 : return nullptr;
581 : }
582 32 : return p;
583 : }
584 64 : const ImageData *Resource::Builder::addImage(StringView key, ImageInfo &&img,
585 : const memory::function<void(uint8_t *, uint64_t, const ImageData::DataCallback &)> &cb, AttachmentLayout layout, AccessType access) {
586 64 : if (!_data) {
587 0 : log::error("Resource", "Fail to add image: ", key, ", not initialized");
588 0 : return nullptr;
589 : }
590 :
591 64 : auto p = Resource_conditionalInsert<ImageData>(_data->images, key, [&, this] () -> ImageData * {
592 32 : auto buf = new (_data->pool) ImageData;
593 32 : static_cast<ImageInfo &>(*buf) = move(img);
594 32 : buf->key = key.pdup(_data->pool);
595 32 : buf->memCallback = cb;
596 32 : buf->targetLayout = layout;
597 32 : buf->targetAccess = access;
598 32 : return buf;
599 64 : }, _data->pool);
600 64 : if (!p) {
601 32 : log::error("Resource", _data->key, ": Image already added: ", key);
602 32 : return nullptr;
603 : }
604 32 : return p;
605 : }
606 :
607 192 : bool Resource::Builder::empty() const {
608 192 : return _data->buffers.empty() && _data->images.empty();
609 : }
610 :
611 : }
|