LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreResource.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 331 399 83.0 %
Date: 2024-05-12 00:16:13 Functions: 49 54 90.7 %

          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             : }

Generated by: LCOV version 1.14