| |
| |
| #ifndef _DEBUG |
| #undef _STLP_DEBUG |
| #else |
| #define _STLP_DEBUG 1 |
| |
| #endif |
| |
| #ifdef TNZCORE_LIGHT |
| #ifdef _DEBUGTOONZ |
| #undef _DEBUGTOONZ |
| #endif |
| #else |
| #ifdef _DEBUG |
| #define _DEBUGTOONZ _DEBUG |
| #endif |
| #endif |
| |
| #include "timagecache.h" |
| #include "trasterimage.h" |
| #ifndef TNZCORE_LIGHT |
| #include "tvectorimage.h" |
| #include "trastercm.h" |
| #include "tropcm.h" |
| #endif |
| |
| #include "tcodec.h" |
| #include "tfilepath_io.h" |
| #include "tconvert.h" |
| #include "tsystem.h" |
| |
| #include "traster.h" |
| |
| |
| #include "tconvert.h" |
| #include "tbigmemorymanager.h" |
| |
| #include "tstream.h" |
| #include "tenv.h" |
| #include <deque> |
| #include <numeric> |
| #include <sstream> |
| #ifdef _WIN32 |
| #include <crtdbg.h> |
| #endif |
| |
| |
| #include <QThreadStorage> |
| |
| |
| |
| #undef DVAPI |
| #undef DVVAR |
| #ifdef TSYSTEM_EXPORTS |
| #define DVAPI DV_EXPORT_API |
| #define DVVAR DV_EXPORT_VAR |
| #else |
| #define DVAPI DV_IMPORT_API |
| #define DVVAR DV_IMPORT_VAR |
| #endif |
| |
| class ImageBuilder; |
| class ImageInfo; |
| |
| |
| |
| TUINT32 HistoryCount = 0; |
| |
| |
| class TheCodec final : public TRasterCodecLz4 { |
| public: |
| static TheCodec *instance() { |
| if (!_instance) _instance = new TheCodec(); |
| |
| return _instance; |
| } |
| |
| void reset() { |
| if (_instance) _instance->TRasterCodecLz4::reset(); |
| } |
| |
| private: |
| static TheCodec *_instance; |
| TheCodec() : TRasterCodecLz4("Lz4_Codec", false) {} |
| }; |
| |
| TheCodec *TheCodec::_instance = 0; |
| |
| |
| |
| class CacheItem : public TSmartObject { |
| DECLARE_CLASS_CODE |
| public: |
| CacheItem() |
| : m_cantCompress(false) |
| , m_builder(0) |
| , m_imageInfo(0) |
| , m_modified(false) {} |
| |
| CacheItem(ImageBuilder *builder, ImageInfo *imageInfo) |
| : m_cantCompress(false) |
| , m_builder(builder) |
| , m_imageInfo(imageInfo) |
| , m_historyCount(0) |
| , m_modified(false) {} |
| |
| virtual ~CacheItem() {} |
| |
| virtual TUINT32 getSize() const = 0; |
| |
| |
| virtual TImageP getImage() const = 0; |
| |
| bool m_cantCompress; |
| ImageBuilder *m_builder; |
| ImageInfo *m_imageInfo; |
| std::string m_id; |
| TUINT32 m_historyCount; |
| bool m_modified; |
| }; |
| |
| #ifdef _WIN32 |
| template class DVAPI TSmartPointerT<CacheItem>; |
| #endif |
| typedef TSmartPointerT<CacheItem> CacheItemP; |
| |
| DEFINE_CLASS_CODE(CacheItem, 101) |
| |
| |
| |
| |
| class ImageInfo { |
| public: |
| TDimension m_size; |
| ImageInfo(const TDimension &size) : m_size(size) {} |
| virtual ~ImageInfo() {} |
| virtual ImageInfo *clone() = 0; |
| }; |
| |
| |
| |
| |
| class ImageBuilder { |
| public: |
| virtual ~ImageBuilder() {} |
| virtual ImageBuilder *clone() = 0; |
| virtual TImageP build(ImageInfo *info, const TRasterP &ras) = 0; |
| }; |
| |
| |
| |
| |
| class RasterImageInfo final : public ImageInfo { |
| public: |
| RasterImageInfo(const TRasterImageP &ri); |
| |
| void setInfo(const TRasterImageP &ri); |
| |
| ImageInfo *clone() override; |
| |
| double m_dpix, m_dpiy; |
| std::string m_name; |
| TRect m_savebox; |
| bool m_isOpaque; |
| TPoint m_offset; |
| int m_subs; |
| }; |
| |
| RasterImageInfo::RasterImageInfo(const TRasterImageP &ri) |
| : ImageInfo(ri->getRaster()->getSize()) { |
| ri->getDpi(m_dpix, m_dpiy); |
| m_name = ri->getName(); |
| m_savebox = ri->getSavebox(); |
| m_isOpaque = ri->isOpaque(); |
| m_offset = ri->getOffset(); |
| m_subs = ri->getSubsampling(); |
| } |
| |
| void RasterImageInfo::setInfo(const TRasterImageP &ri) { |
| ri->setDpi(m_dpix, m_dpiy); |
| ri->setName(m_name); |
| ri->setSavebox(m_savebox); |
| ri->setOpaqueFlag(m_isOpaque); |
| ri->setOffset(m_offset); |
| ri->setSubsampling(m_subs); |
| } |
| |
| ImageInfo *RasterImageInfo::clone() { return new RasterImageInfo(*this); } |
| |
| |
| |
| #ifndef TNZCORE_LIGHT |
| |
| #include "tpalette.h" |
| #include "ttoonzimage.h" |
| |
| class ToonzImageInfo final : public ImageInfo { |
| public: |
| ToonzImageInfo(const TToonzImageP &ti); |
| ~ToonzImageInfo() { |
| if (m_palette) m_palette->release(); |
| } |
| |
| ImageInfo *clone() override { |
| ToonzImageInfo *ret = new ToonzImageInfo(*this); |
| if (ret->m_palette) ret->m_palette->addRef(); |
| return ret; |
| } |
| |
| void setInfo(const TToonzImageP &ti); |
| |
| double m_dpix, m_dpiy; |
| std::string m_name; |
| TRect m_savebox; |
| TPoint m_offset; |
| int m_subs; |
| TPalette *m_palette; |
| }; |
| |
| ToonzImageInfo::ToonzImageInfo(const TToonzImageP &ti) |
| : ImageInfo(ti->getSize()) { |
| m_palette = ti->getPalette(); |
| if (m_palette) m_palette->addRef(); |
| |
| ti->getDpi(m_dpix, m_dpiy); |
| m_savebox = ti->getSavebox(); |
| m_offset = ti->getOffset(); |
| m_subs = ti->getSubsampling(); |
| } |
| |
| void ToonzImageInfo::setInfo(const TToonzImageP &ti) { |
| ti->setPalette(m_palette); |
| ti->setDpi(m_dpix, m_dpiy); |
| ti->setOffset(m_offset); |
| ti->setSubsampling(m_subs); |
| } |
| |
| #endif |
| |
| |
| |
| |
| class RasterImageBuilder final : public ImageBuilder { |
| public: |
| ImageBuilder *clone() override { return new RasterImageBuilder(*this); } |
| |
| TImageP build(ImageInfo *info, const TRasterP &ras) override; |
| }; |
| |
| TImageP RasterImageBuilder::build(ImageInfo *info, const TRasterP &ras) { |
| RasterImageInfo *riInfo = dynamic_cast<RasterImageInfo *>(info); |
| assert(riInfo); |
| |
| int rcount = ras->getRefCount(); |
| TRasterImageP ri = new TRasterImage(); |
| #ifdef _DEBUGTOONZ |
| ras->m_cashed = true; |
| #endif |
| ri->setRaster(ras); |
| riInfo->setInfo(ri); |
| assert(ras->getRefCount() > rcount); |
| return ri; |
| } |
| |
| |
| |
| #ifndef TNZCORE_LIGHT |
| |
| class ToonzImageBuilder final : public ImageBuilder { |
| public: |
| ImageBuilder *clone() override { return new ToonzImageBuilder(*this); } |
| |
| TImageP build(ImageInfo *info, const TRasterP &ras) override; |
| }; |
| |
| TImageP ToonzImageBuilder::build(ImageInfo *info, const TRasterP &ras) { |
| ToonzImageInfo *tiInfo = dynamic_cast<ToonzImageInfo *>(info); |
| assert(tiInfo); |
| |
| TRasterCM32P rasCM32 = ras; |
| assert(rasCM32); |
| |
| TRasterCM32P imgRasCM32; |
| |
| assert(TRect(tiInfo->m_size).contains(tiInfo->m_savebox)); |
| |
| if (ras->getSize() != tiInfo->m_size) { |
| TRasterCM32P fullRas(tiInfo->m_size); |
| TRect rectToExtract(tiInfo->m_savebox); |
| TPixelCM32 bgColor; |
| fullRas->fillOutside(tiInfo->m_savebox, bgColor); |
| fullRas->extractT(rectToExtract)->copy(ras); |
| assert(rectToExtract == tiInfo->m_savebox); |
| imgRasCM32 = fullRas; |
| } else |
| imgRasCM32 = rasCM32; |
| #ifdef _DEBUG |
| imgRasCM32->m_cashed = true; |
| #endif |
| TToonzImageP ti = new TToonzImage(imgRasCM32, tiInfo->m_savebox); |
| tiInfo->setInfo(ti); |
| return ti; |
| } |
| #endif |
| |
| |
| |
| class UncompressedOnMemoryCacheItem final : public CacheItem { |
| public: |
| UncompressedOnMemoryCacheItem(const TImageP &image) : m_image(image) { |
| TRasterImageP ri = m_image; |
| |
| if (ri) m_imageInfo = new RasterImageInfo(ri); |
| #ifndef TNZCORE_LIGHT |
| else { |
| TToonzImageP ti = m_image; |
| if (ti) |
| m_imageInfo = new ToonzImageInfo(ti); |
| else |
| m_imageInfo = 0; |
| } |
| #else |
| else |
| m_imageInfo = 0; |
| #endif |
| } |
| |
| ~UncompressedOnMemoryCacheItem() { |
| if (m_imageInfo) delete m_imageInfo; |
| } |
| |
| TUINT32 getSize() const override; |
| TImageP getImage() const override { return m_image; } |
| |
| TImageP m_image; |
| }; |
| |
| #ifdef _WIN32 |
| template class DVAPI TSmartPointerT<UncompressedOnMemoryCacheItem>; |
| template class DVAPI |
| TDerivedSmartPointerT<UncompressedOnMemoryCacheItem, CacheItem>; |
| #endif |
| typedef TDerivedSmartPointerT<UncompressedOnMemoryCacheItem, CacheItem> |
| UncompressedOnMemoryCacheItemP; |
| |
| |
| |
| TUINT32 UncompressedOnMemoryCacheItem::getSize() const { |
| TRasterImageP ri = m_image; |
| if (ri) { |
| TRasterP ras = ri->getRaster(); |
| if (ras) |
| return ras->getLy() * ras->getRowSize(); |
| else |
| return 0; |
| } else { |
| #ifndef TNZCORE_LIGHT |
| TToonzImageP ti = m_image; |
| if (ti) { |
| TDimension size = ti->getSize(); |
| return size.lx * size.ly * sizeof(TPixelCM32); |
| } |
| #endif |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| class CompressedOnMemoryCacheItem final : public CacheItem { |
| public: |
| CompressedOnMemoryCacheItem(const TImageP &img); |
| |
| CompressedOnMemoryCacheItem(const TRasterP &compressedRas, |
| ImageBuilder *builder, ImageInfo *info); |
| |
| ~CompressedOnMemoryCacheItem(); |
| |
| TUINT32 getSize() const override; |
| TImageP getImage() const override; |
| |
| TRasterP m_compressedRas; |
| }; |
| |
| #ifdef _WIN32 |
| template class DVAPI TSmartPointerT<CompressedOnMemoryCacheItem>; |
| template class DVAPI |
| TDerivedSmartPointerT<CompressedOnMemoryCacheItem, CacheItem>; |
| #endif |
| typedef TDerivedSmartPointerT<CompressedOnMemoryCacheItem, CacheItem> |
| CompressedOnMemoryCacheItemP; |
| |
| |
| |
| CompressedOnMemoryCacheItem::CompressedOnMemoryCacheItem(const TImageP &img) |
| : m_compressedRas() { |
| TRasterImageP ri = img; |
| if (ri) { |
| m_imageInfo = new RasterImageInfo(ri); |
| m_builder = new RasterImageBuilder(); |
| TINT32 buffSize = 0; |
| m_compressedRas = |
| TheCodec::instance()->compress(ri->getRaster(), 1, buffSize); |
| } |
| #ifndef TNZCORE_LIGHT |
| else { |
| TToonzImageP ti = img; |
| if (ti) { |
| m_imageInfo = new ToonzImageInfo(ti); |
| m_builder = new ToonzImageBuilder(); |
| TRasterCM32P rasCM32 = ti->getRaster(); |
| TINT32 buffSize = 0; |
| m_compressedRas = TheCodec::instance()->compress(rasCM32, 1, buffSize); |
| } else |
| assert(false); |
| } |
| #else |
| else |
| assert(false); |
| #endif |
| } |
| |
| |
| |
| CompressedOnMemoryCacheItem::CompressedOnMemoryCacheItem(const TRasterP &ras, |
| ImageBuilder *builder, |
| ImageInfo *info) |
| : CacheItem(builder, info), m_compressedRas(ras) {} |
| |
| |
| |
| CompressedOnMemoryCacheItem::~CompressedOnMemoryCacheItem() { |
| delete m_imageInfo; |
| } |
| |
| |
| |
| TUINT32 CompressedOnMemoryCacheItem::getSize() const { |
| if (m_compressedRas) |
| return m_compressedRas->getLx(); |
| else |
| return 0; |
| } |
| |
| |
| |
| TImageP CompressedOnMemoryCacheItem::getImage() const { |
| assert(m_compressedRas); |
| |
| |
| TRasterP ras; |
| |
| TheCodec::instance()->decompress(m_compressedRas, ras); |
| #ifdef _DEBUGTOONZ |
| ras->m_cashed = true; |
| #endif |
| #ifndef TNZCORE_LIGHT |
| ToonzImageBuilder *tibuilder = dynamic_cast<ToonzImageBuilder *>(m_builder); |
| if (tibuilder) |
| return tibuilder->build(m_imageInfo, ras); |
| else |
| #endif |
| return m_builder->build(m_imageInfo, ras); |
| } |
| |
| |
| |
| class CompressedOnDiskCacheItem final : public CacheItem { |
| public: |
| CompressedOnDiskCacheItem(const TFilePath &fp, const TRasterP &compressedRas, |
| ImageBuilder *builder, ImageInfo *info); |
| |
| ~CompressedOnDiskCacheItem(); |
| |
| TUINT32 getSize() const override { return 0; } |
| TImageP getImage() const override; |
| TFilePath m_fp; |
| }; |
| |
| #ifdef _WIN32 |
| template class DVAPI TSmartPointerT<CompressedOnDiskCacheItem>; |
| template class DVAPI |
| TDerivedSmartPointerT<CompressedOnDiskCacheItem, CacheItem>; |
| #endif |
| typedef TDerivedSmartPointerT<CompressedOnDiskCacheItem, CacheItem> |
| CompressedOnDiskCacheItemP; |
| |
| |
| |
| CompressedOnDiskCacheItem::CompressedOnDiskCacheItem( |
| const TFilePath &fp, const TRasterP &compressedRas, ImageBuilder *builder, |
| ImageInfo *info) |
| : CacheItem(builder, info), m_fp(fp) { |
| compressedRas->lock(); |
| |
| Tofstream oss(m_fp); |
| assert(compressedRas->getLy() == 1 && compressedRas->getPixelSize() == 1); |
| TUINT32 size = compressedRas->getLx(); |
| oss.write((char *)&size, sizeof(TUINT32)); |
| oss.write((char *)compressedRas->getRawData(), size); |
| assert(!oss.fail()); |
| |
| compressedRas->unlock(); |
| } |
| |
| |
| |
| CompressedOnDiskCacheItem::~CompressedOnDiskCacheItem() { |
| delete m_imageInfo; |
| TSystem::deleteFile(m_fp); |
| } |
| |
| |
| |
| TImageP CompressedOnDiskCacheItem::getImage() const { |
| Tifstream is(m_fp); |
| TUINT32 dataSize; |
| is.read((char *)&dataSize, sizeof(TUINT32)); |
| TRasterGR8P ras(dataSize, 1); |
| ras->lock(); |
| UCHAR *data = ras->getRawData(); |
| is.read((char *)data, dataSize); |
| assert(!is.fail()); |
| ras->unlock(); |
| CompressedOnMemoryCacheItem item(ras, m_builder->clone(), |
| m_imageInfo->clone()); |
| return item.getImage(); |
| } |
| |
| |
| |
| class UncompressedOnDiskCacheItem final : public CacheItem { |
| int m_pixelsize; |
| |
| public: |
| UncompressedOnDiskCacheItem(const TFilePath &fp, const TImageP &img); |
| |
| ~UncompressedOnDiskCacheItem(); |
| |
| TUINT32 getSize() const override { return 0; } |
| TImageP getImage() const override; |
| |
| |
| TFilePath m_fp; |
| }; |
| #ifdef _WIN32 |
| template class DVAPI TSmartPointerT<UncompressedOnDiskCacheItem>; |
| template class DVAPI |
| TDerivedSmartPointerT<UncompressedOnDiskCacheItem, CacheItem>; |
| #endif |
| typedef TDerivedSmartPointerT<UncompressedOnDiskCacheItem, CacheItem> |
| UncompressedOnDiskCacheItemP; |
| |
| |
| |
| UncompressedOnDiskCacheItem::UncompressedOnDiskCacheItem(const TFilePath &fp, |
| const TImageP &image) |
| : CacheItem(0, 0), m_fp(fp) { |
| TRasterImageP ri = image; |
| |
| TRasterP ras; |
| if (ri) { |
| m_imageInfo = new RasterImageInfo(ri); |
| ras = ri->getRaster(); |
| } |
| #ifndef TNZCORE_LIGHT |
| else { |
| TToonzImageP ti = image; |
| if (ti) { |
| m_imageInfo = new ToonzImageInfo(ti); |
| ras = ti->getRaster(); |
| } else |
| assert(false); |
| } |
| #else |
| else |
| assert(false); |
| #endif |
| |
| m_builder = 0; |
| |
| int dataSize = ras->getLx() * ras->getLy() * ras->getPixelSize(); |
| |
| int lx = ras->getLx(); |
| int ly = ras->getLy(); |
| int wrap = ras->getWrap(); |
| m_pixelsize = ras->getPixelSize(); |
| |
| Tofstream oss(m_fp); |
| |
| |
| ras->lock(); |
| if (lx == wrap) { |
| oss.write((char *)ras->getRawData(), dataSize); |
| assert(!oss.fail()); |
| } else { |
| char *buf = (char *)ras->getRawData(); |
| for (int i = 0; i < ly; i++, buf += wrap) { |
| oss.write(buf, lx * m_pixelsize); |
| assert(!oss.fail()); |
| } |
| } |
| ras->unlock(); |
| } |
| |
| |
| |
| UncompressedOnDiskCacheItem::~UncompressedOnDiskCacheItem() { |
| delete m_imageInfo; |
| TSystem::deleteFile(m_fp); |
| } |
| |
| |
| |
| TImageP UncompressedOnDiskCacheItem::getImage() const { |
| Tifstream is(m_fp); |
| TUINT32 dataSize = |
| m_imageInfo->m_size.lx * m_imageInfo->m_size.ly * m_pixelsize; |
| |
| |
| |
| |
| TRasterP ras; |
| |
| RasterImageInfo *rii = dynamic_cast<RasterImageInfo *>(m_imageInfo); |
| |
| if (rii) { |
| if (m_pixelsize == 4) |
| ras = (TRasterP)(TRaster32P(rii->m_size)); |
| else if (m_pixelsize == 8) |
| ras = (TRasterP)(TRaster64P(rii->m_size)); |
| else if (m_pixelsize == 1) |
| ras = (TRasterP)(TRasterGR8P(rii->m_size)); |
| else if (m_pixelsize == 2) |
| ras = (TRasterP)(TRasterGR16P(rii->m_size)); |
| else |
| assert(false); |
| ras->lock(); |
| char *data = (char *)ras->getRawData(); |
| is.read(data, dataSize); |
| ras->unlock(); |
| #ifdef _DEBUGTOONZ |
| ras->m_cashed = true; |
| #endif |
| |
| return RasterImageBuilder().build(m_imageInfo, ras); |
| } |
| #ifndef TNZCORE_LIGHT |
| else { |
| ToonzImageInfo *tii = dynamic_cast<ToonzImageInfo *>(m_imageInfo); |
| if (tii) { |
| ras = (TRasterP)(TRasterCM32P(tii->m_size)); |
| ras->lock(); |
| char *data = (char *)ras->getRawData(); |
| is.read(data, dataSize); |
| ras->unlock(); |
| #ifdef _DEBUG |
| ras->m_cashed = true; |
| #endif |
| |
| return ToonzImageBuilder().build(m_imageInfo, ras); |
| } else { |
| assert(false); |
| return 0; |
| } |
| } |
| #else |
| else { |
| assert(false); |
| return 0; |
| } |
| #endif |
| } |
| |
| |
| |
| std::string TImageCache::getUniqueId(void) { |
| static TAtomicVar count; |
| std::stringstream ss; |
| ss << ++count; |
| return "IMAGECACHEUNIQUEID" + ss.str(); |
| } |
| |
| class TImageCache::Imp { |
| public: |
| Imp() : m_rootDir() { |
| |
| |
| |
| if (TBigMemoryManager::instance()->isActive()) return; |
| |
| m_reservedMemory = (TINT64)(TSystem::getMemorySize(true) * 0.10); |
| if (m_reservedMemory < 64 * 1024) m_reservedMemory = 64 * 1024; |
| } |
| |
| ~Imp() { |
| if (m_rootDir != TFilePath()) TSystem::rmDirTree(m_rootDir); |
| } |
| |
| bool inline notEnoughMemory() { |
| if (TBigMemoryManager::instance()->isActive()) |
| return TBigMemoryManager::instance()->getAvailableMemoryinKb() < |
| 50 * 1024; |
| else |
| return TSystem::memoryShortage(); |
| } |
| |
| void doCompress(); |
| void doCompress(std::string id); |
| UCHAR *compressAndMalloc(TUINT32 requestedSize); |
| |
| |
| void outputMap(UINT chunkRequested, std::string filename); |
| void remove(const std::string &id); |
| void remap(const std::string &dstId, const std::string &srcId); |
| TImageP get(const std::string &id, bool toBeModified); |
| void add(const std::string &id, const TImageP &img, bool overwrite); |
| TFilePath m_rootDir; |
| |
| #ifndef TNZCORE_LIGHT |
| QThreadStorage<bool *> m_isEnabled; |
| #else |
| bool m_isEnabled; |
| #endif |
| |
| std::map<std::string, CacheItemP> m_uncompressedItems; |
| std::map<TUINT32, std::string> m_itemHistory; |
| std::map<std::string, CacheItemP> m_compressedItems; |
| std::map<void *, std::string> |
| m_itemsByImagePointer; |
| std::map<std::string, std::string> m_duplicatedItems; |
| |
| |
| |
| |
| |
| TINT64 m_reservedMemory; |
| TThread::Mutex m_mutex; |
| |
| static int m_fileid; |
| }; |
| |
| int TImageCache::Imp::m_fileid; |
| |
| |
| namespace { |
| inline void *getPointer(const TImageP &img) { |
| TRasterImageP rimg = img; |
| if (rimg) return rimg->getRaster().getPointer(); |
| #ifndef TNZCORE_LIGHT |
| TToonzImageP timg = img; |
| if (timg) return timg->getRaster().getPointer(); |
| #endif |
| |
| return img.getPointer(); |
| } |
| |
| |
| |
| inline TINT32 hasExternalReferences(const TImageP &img) { |
| int refCount; |
| |
| { |
| TRasterImageP rimg = img; |
| if (rimg) refCount = rimg->getRaster()->getRefCount(); |
| } |
| |
| #ifndef TNZCORE_LIGHT |
| { |
| TToonzImageP timg = img; |
| if (timg) |
| refCount = timg->getRaster()->getRefCount() - |
| 1; |
| |
| } |
| #endif |
| |
| return std::max(refCount, img->getRefCount()) > 1; |
| } |
| } |
| |
| |
| void TImageCache::Imp::doCompress() { |
| |
| |
| |
| |
| |
| |
| |
| TThread::MutexLocker sl(&m_mutex); |
| |
| std::map<TUINT32, std::string>::iterator itu = m_itemHistory.begin(); |
| |
| for (; itu != m_itemHistory.end() && notEnoughMemory();) { |
| std::map<std::string, CacheItemP>::iterator it = |
| m_uncompressedItems.find(itu->second); |
| assert(it != m_uncompressedItems.end()); |
| CacheItemP item = it->second; |
| |
| UncompressedOnMemoryCacheItemP uitem = item; |
| if (item->m_cantCompress || |
| (uitem && (!uitem->m_image || hasExternalReferences(uitem->m_image)))) { |
| ++itu; |
| continue; |
| } |
| std::string id = it->first; |
| |
| #ifdef _WIN32 |
| assert(itu->first == it->second->m_historyCount); |
| itu = m_itemHistory.erase(itu); |
| m_itemsByImagePointer.erase(getPointer(item->getImage())); |
| m_uncompressedItems.erase(it); |
| #else |
| std::map<TUINT32, std::string>::iterator itu2 = itu; |
| itu++; |
| m_itemHistory.erase(itu2); |
| m_itemsByImagePointer.erase(item->getImage().getPointer()); |
| m_uncompressedItems.erase(it); |
| #endif |
| |
| if (m_compressedItems.find(id) == m_compressedItems.end()) { |
| assert(uitem); |
| item->m_cantCompress = true; |
| CacheItemP newItem = new CompressedOnMemoryCacheItem( |
| item->getImage()); |
| |
| item->m_cantCompress = false; |
| if (newItem->getSize() == |
| 0) |
| { |
| assert(m_rootDir != TFilePath()); |
| TFilePath fp = |
| m_rootDir + TFilePath(std::to_string(TImageCache::Imp::m_fileid++)); |
| newItem = new UncompressedOnDiskCacheItem(fp, item->getImage()); |
| } |
| m_compressedItems[id] = newItem; |
| item = CacheItemP(); |
| uitem = UncompressedOnMemoryCacheItemP(); |
| |
| |
| |
| itu = m_itemHistory.begin(); |
| } |
| } |
| |
| |
| |
| |
| |
| if (itu != m_itemHistory.end()) |
| return; |
| |
| std::map<std::string, CacheItemP>::iterator itc = m_compressedItems.begin(); |
| for (; itc != m_compressedItems.end() && notEnoughMemory(); ++itc) { |
| CacheItemP item = itc->second; |
| if (item->m_cantCompress) continue; |
| |
| CompressedOnMemoryCacheItemP citem = itc->second; |
| if (citem) { |
| assert(m_rootDir != TFilePath()); |
| TFilePath fp = |
| m_rootDir + TFilePath(std::to_string(TImageCache::Imp::m_fileid++)); |
| |
| CacheItemP newItem = new CompressedOnDiskCacheItem( |
| fp, citem->m_compressedRas, citem->m_builder->clone(), |
| citem->m_imageInfo->clone()); |
| |
| itc->second = 0; |
| m_compressedItems[itc->first] = newItem; |
| } |
| } |
| } |
| |
| |
| |
| void TImageCache::Imp::doCompress(std::string id) { |
| TThread::MutexLocker sl(&m_mutex); |
| |
| |
| std::map<std::string, CacheItemP>::iterator it = m_uncompressedItems.find(id); |
| if (it == m_uncompressedItems.end()) return; |
| |
| |
| CacheItemP item = it->second; |
| UncompressedOnMemoryCacheItemP uitem = item; |
| if (item->m_cantCompress || |
| (uitem && (!uitem->m_image || hasExternalReferences(uitem->m_image)))) |
| return; |
| |
| |
| std::map<TUINT32, std::string>::iterator itu = m_itemHistory.begin(); |
| while (itu != m_itemHistory.end() && itu->second != id) ++itu; |
| if (itu == m_itemHistory.end()) return; |
| |
| |
| #ifdef _WIN32 |
| assert(itu->first == it->second->m_historyCount); |
| itu = m_itemHistory.erase(itu); |
| m_itemsByImagePointer.erase(getPointer(item->getImage())); |
| #else |
| std::map<TUINT32, std::string>::iterator itu2 = itu; |
| itu++; |
| m_itemHistory.erase(itu2); |
| m_itemsByImagePointer.erase(item->getImage().getPointer()); |
| #endif |
| |
| |
| m_uncompressedItems.erase(it); |
| |
| |
| if (m_compressedItems.find(id) != m_compressedItems.end()) return; |
| |
| assert(uitem); |
| item->m_cantCompress = true; |
| CacheItemP newItem = new CompressedOnMemoryCacheItem( |
| item->getImage()); |
| |
| item->m_cantCompress = false; |
| if (newItem->getSize() == |
| 0) |
| { |
| assert(m_rootDir != TFilePath()); |
| TFilePath fp = |
| m_rootDir + TFilePath(std::to_string(TImageCache::Imp::m_fileid++)); |
| newItem = new UncompressedOnDiskCacheItem(fp, item->getImage()); |
| } |
| m_compressedItems[id] = newItem; |
| item = CacheItemP(); |
| uitem = UncompressedOnMemoryCacheItemP(); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| UCHAR *TImageCache::Imp::compressAndMalloc(TUINT32 size) { |
| UCHAR *buf = 0; |
| |
| TThread::MutexLocker sl(&m_mutex); |
| |
| TheCodec::instance()->reset(); |
| |
| |
| |
| |
| |
| |
| std::map<TUINT32, std::string>::iterator itu = m_itemHistory.begin(); |
| while ( |
| (buf = TBigMemoryManager::instance()->getBuffer(size)) == 0 && |
| itu != |
| m_itemHistory |
| .end()) |
| { |
| std::map<std::string, CacheItemP>::iterator it = |
| m_uncompressedItems.find(itu->second); |
| assert(it != m_uncompressedItems.end()); |
| CacheItemP item = it->second; |
| |
| UncompressedOnMemoryCacheItemP uitem = item; |
| if (item->m_cantCompress || |
| (uitem && (!uitem->m_image || hasExternalReferences(uitem->m_image)))) { |
| ++itu; |
| continue; |
| } |
| |
| if (m_compressedItems.find(it->first) == m_compressedItems.end()) { |
| assert(uitem); |
| CacheItemP newItem; |
| |
| |
| |
| assert(m_rootDir != TFilePath()); |
| TFilePath fp = |
| m_rootDir + TFilePath(std::to_string(TImageCache::Imp::m_fileid++)); |
| newItem = new UncompressedOnDiskCacheItem(fp, item->getImage()); |
| |
| |
| m_compressedItems[it->first] = newItem; |
| } |
| |
| #ifdef _WIN32 |
| assert(itu->first == it->second->m_historyCount); |
| itu = m_itemHistory.erase(itu); |
| m_itemsByImagePointer.erase(getPointer(item->getImage())); |
| m_uncompressedItems.erase(it); |
| #else |
| std::map<TUINT32, std::string>::iterator itu2 = itu; |
| itu++; |
| m_itemHistory.erase(itu2); |
| m_itemsByImagePointer.erase(item->getImage().getPointer()); |
| m_uncompressedItems.erase(it); |
| #endif |
| } |
| |
| if (buf != 0) return buf; |
| |
| std::map<std::string, CacheItemP>::iterator itc = m_compressedItems.begin(); |
| for (; itc != m_compressedItems.end() && |
| (buf = TBigMemoryManager::instance()->getBuffer(size)) == 0; |
| ++itc) { |
| CacheItemP item = itc->second; |
| if (item->m_cantCompress) continue; |
| |
| CompressedOnMemoryCacheItemP citem = itc->second; |
| if (citem) { |
| assert(m_rootDir != TFilePath()); |
| TFilePath fp = |
| m_rootDir + TFilePath(std::to_string(TImageCache::Imp::m_fileid++)); |
| |
| CacheItemP newItem = new CompressedOnDiskCacheItem( |
| fp, citem->m_compressedRas, citem->m_builder->clone(), |
| citem->m_imageInfo->clone()); |
| |
| itc->second = 0; |
| m_compressedItems[itc->first] = newItem; |
| } |
| } |
| |
| return buf; |
| } |
| |
| |
| |
| namespace { |
| |
| int check = 0; |
| const int magic = 123456; |
| } |
| |
| static TImageCache *CacheInstance = 0; |
| |
| TImageCache *TImageCache::instance() { |
| if (CacheInstance == 0) CacheInstance = new TImageCache(); |
| return CacheInstance; |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| TImageCache::TImageCache() : m_imp(new Imp()) { |
| assert(check == 0); |
| check = magic; |
| } |
| |
| |
| |
| TImageCache::~TImageCache() { |
| assert(check == magic); |
| check = -1; |
| CacheInstance = 0; |
| } |
| |
| |
| |
| void TImageCache::setEnabled(bool isEnabled) { |
| #ifndef TNZCORE_LIGHT |
| QThreadStorage<bool *> &storage = m_imp->m_isEnabled; |
| |
| if (storage.hasLocalData() && *(storage.localData()) == isEnabled) return; |
| if (!storage.hasLocalData()) |
| storage.setLocalData(new bool(isEnabled)); |
| else |
| *(storage.localData()) = isEnabled; |
| #else |
| m_imp->m_isEnabled = isEnabled; |
| #endif |
| } |
| |
| |
| |
| bool TImageCache::isEnabled() { |
| #ifndef TNZCORE_LIGHT |
| QThreadStorage<bool *> &storage = m_imp->m_isEnabled; |
| |
| if (!storage.hasLocalData()) return true; |
| return *(storage.localData()); |
| #else |
| return m_isEnabled; |
| #endif |
| } |
| |
| |
| |
| void TImageCache::setRootDir(const TFilePath &cacheDir) { |
| if (m_imp->m_rootDir != TFilePath()) return; |
| |
| m_imp->m_rootDir = |
| cacheDir + TFilePath(std::to_string(TSystem::getProcessId())); |
| |
| #ifndef TNZCORE_LIGHT |
| TFileStatus fs1(m_imp->m_rootDir); |
| |
| if (!fs1.doesExist()) TSystem::mkDir(m_imp->m_rootDir); |
| |
| #endif |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| UCHAR *TImageCache::compressAndMalloc(TUINT32 requestedSize) { |
| return m_imp->compressAndMalloc(requestedSize); |
| } |
| |
| |
| |
| void TImageCache::add(const std::string &id, const TImageP &img, |
| bool overwrite) { |
| if (!isEnabled()) return; |
| m_imp->add(id, img, overwrite); |
| } |
| |
| |
| |
| void TImageCache::Imp::add(const std::string &id, const TImageP &img, |
| bool overwrite) { |
| TThread::MutexLocker sl(&m_mutex); |
| |
| #ifdef LEVO |
| std::map<std::string, CacheItemP>::iterator it1 = m_uncompressedItems.begin(); |
| |
| for (; it1 != m_uncompressedItems.end(); ++it1) { |
| UncompressedOnMemoryCacheItemP item = |
| (UncompressedOnMemoryCacheItemP)it1->second; |
| |
| assert(item); |
| TImageP refImg = item->getImage(); |
| if (refImg.getPointer() == img.getPointer() && it1->first != id) |
| assert(!"opps gia' esiste in cache!"); |
| } |
| #endif |
| |
| std::map<std::string, CacheItemP>::iterator itUncompr = |
| m_uncompressedItems.find(id); |
| std::map<std::string, CacheItemP>::iterator itCompr = |
| m_compressedItems.find(id); |
| |
| #ifdef _DEBUGTOONZ |
| TRasterImageP rimg = (TRasterImageP)img; |
| TToonzImageP timg = (TToonzImageP)img; |
| #endif |
| |
| if (itUncompr != m_uncompressedItems.end() || |
| itCompr != |
| m_compressedItems.end()) |
| { |
| if (overwrite) { |
| #ifdef _DEBUGTOONZ |
| if (rimg) |
| rimg->getRaster()->m_cashed = true; |
| else if (timg) |
| timg->getRaster()->m_cashed = true; |
| #endif |
| std::map<std::string, CacheItemP>::iterator it; |
| |
| if (itUncompr != m_uncompressedItems.end()) { |
| assert(m_itemHistory.find(itUncompr->second->m_historyCount) != |
| m_itemHistory.end()); |
| m_itemHistory.erase(itUncompr->second->m_historyCount); |
| m_itemsByImagePointer.erase(getPointer(itUncompr->second->getImage())); |
| m_uncompressedItems.erase(itUncompr); |
| } |
| if (itCompr != m_compressedItems.end()) m_compressedItems.erase(id); |
| } else |
| return; |
| } else { |
| std::map<std::string, std::string>::iterator dt = |
| m_duplicatedItems.find(id); |
| if ((dt != m_duplicatedItems.end()) && !overwrite) return; |
| |
| std::map<void *, std::string>::iterator it; |
| if ((it = m_itemsByImagePointer.find(getPointer(img))) != |
| m_itemsByImagePointer |
| .end()) |
| { |
| m_duplicatedItems[id] = it->second; |
| return; |
| } |
| |
| if (dt != m_duplicatedItems.end()) m_duplicatedItems.erase(dt); |
| } |
| |
| CacheItemP item; |
| |
| #ifdef _DEBUGTOONZ |
| if (rimg) |
| rimg->getRaster()->m_cashed = true; |
| else if (timg) |
| timg->getRaster()->m_cashed = true; |
| #endif |
| |
| item = new UncompressedOnMemoryCacheItem(img); |
| #ifdef TNZCORE_LIGHT |
| item->m_cantCompress = false; |
| #else |
| item->m_cantCompress = (TVectorImageP(img) ? true : false); |
| #endif |
| item->m_id = id; |
| m_uncompressedItems[id] = item; |
| m_itemsByImagePointer[getPointer(img)] = id; |
| item->m_historyCount = HistoryCount; |
| m_itemHistory[HistoryCount] = id; |
| HistoryCount++; |
| |
| doCompress(); |
| |
| #ifdef _DEBUGTOONZ |
| |
| |
| |
| #endif |
| } |
| |
| void TImageCache::remove(const std::string &id) { m_imp->remove(id); } |
| |
| |
| |
| void TImageCache::Imp::remove(const std::string &id) { |
| if (CacheInstance == 0) |
| return; |
| |
| |
| assert(check == magic); |
| TThread::MutexLocker sl(&m_mutex); |
| |
| std::map<std::string, std::string>::iterator it1; |
| if ((it1 = m_duplicatedItems.find(id)) != |
| m_duplicatedItems.end()) |
| { |
| m_duplicatedItems.erase(it1); |
| return; |
| } |
| |
| for (it1 = m_duplicatedItems.begin(); it1 != m_duplicatedItems.end(); ++it1) |
| if (it1->second == id) break; |
| |
| if (it1 != m_duplicatedItems.end()) |
| |
| |
| { |
| std::string sonId = it1->first; |
| m_duplicatedItems.erase(it1); |
| remap(sonId, id); |
| return; |
| } |
| |
| std::map<std::string, CacheItemP>::iterator it = m_uncompressedItems.find(id); |
| std::map<std::string, CacheItemP>::iterator itc = m_compressedItems.find(id); |
| if (it != m_uncompressedItems.end()) { |
| const CacheItemP &item = it->second; |
| assert((UncompressedOnMemoryCacheItemP)item); |
| assert(m_itemHistory.find(it->second->m_historyCount) != |
| m_itemHistory.end()); |
| m_itemHistory.erase(it->second->m_historyCount); |
| m_itemsByImagePointer.erase(getPointer(it->second->getImage())); |
| |
| #ifdef _DEBUGTOONZ |
| if ((TRasterImageP)it->second->getImage()) |
| ((TRasterImageP)it->second->getImage())->getRaster()->m_cashed = false; |
| else if ((TToonzImageP)it->second->getImage()) |
| ((TToonzImageP)it->second->getImage())->getRaster()->m_cashed = false; |
| #endif |
| |
| m_uncompressedItems.erase(it); |
| } |
| if (itc != m_compressedItems.end()) m_compressedItems.erase(itc); |
| } |
| |
| |
| |
| void TImageCache::remap(const std::string &dstId, const std::string &srcId) { |
| m_imp->remap(dstId, srcId); |
| } |
| |
| void TImageCache::Imp::remap(const std::string &dstId, |
| const std::string &srcId) { |
| TThread::MutexLocker sl(&m_mutex); |
| std::map<std::string, CacheItemP>::iterator it = |
| m_uncompressedItems.find(srcId); |
| if (it != m_uncompressedItems.end()) { |
| CacheItemP citem = it->second; |
| assert(m_itemHistory.find(citem->m_historyCount) != m_itemHistory.end()); |
| m_itemHistory.erase(citem->m_historyCount); |
| m_itemsByImagePointer.erase(getPointer(citem->getImage())); |
| m_uncompressedItems.erase(it); |
| |
| m_uncompressedItems[dstId] = citem; |
| m_itemHistory[citem->m_historyCount] = dstId; |
| m_itemsByImagePointer[getPointer(citem->getImage())] = dstId; |
| } |
| it = m_compressedItems.find(srcId); |
| if (it != m_compressedItems.end()) { |
| CacheItemP citem = it->second; |
| m_compressedItems.erase(it); |
| m_compressedItems[dstId] = citem; |
| } |
| std::map<std::string, std::string>::iterator it2 = |
| m_duplicatedItems.find(srcId); |
| if (it2 != m_duplicatedItems.end()) { |
| std::string id = it2->second; |
| m_duplicatedItems.erase(it2); |
| m_duplicatedItems[dstId] = id; |
| } |
| for (it2 = m_duplicatedItems.begin(); it2 != m_duplicatedItems.end(); ++it2) |
| if (it2->second == srcId) it2->second = dstId; |
| } |
| |
| |
| |
| void TImageCache::remapIcons(const std::string &dstId, |
| const std::string &srcId) { |
| std::map<std::string, CacheItemP>::iterator it; |
| std::map<std::string, std::string> table; |
| std::string prefix = srcId + ":"; |
| int j = (int)prefix.length(); |
| for (it = m_imp->m_uncompressedItems.begin(); |
| it != m_imp->m_uncompressedItems.end(); ++it) { |
| std::string id = it->first; |
| if (id.find(prefix) == 0) table[id] = dstId + ":" + id.substr(j); |
| } |
| for (std::map<std::string, std::string>::iterator it2 = table.begin(); |
| it2 != table.end(); ++it2) { |
| remap(it2->second, it2->first); |
| } |
| } |
| |
| |
| |
| void TImageCache::clear(bool deleteFolder) { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| m_imp->m_uncompressedItems.clear(); |
| m_imp->m_itemHistory.clear(); |
| m_imp->m_compressedItems.clear(); |
| m_imp->m_duplicatedItems.clear(); |
| m_imp->m_itemsByImagePointer.clear(); |
| if (deleteFolder && m_imp->m_rootDir != TFilePath()) |
| TSystem::rmDirTree(m_imp->m_rootDir); |
| } |
| |
| |
| |
| void TImageCache::clearSceneImages() { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| |
| |
| m_imp->m_uncompressedItems.erase( |
| m_imp->m_uncompressedItems.begin(), |
| m_imp->m_uncompressedItems.lower_bound("$:")); |
| m_imp->m_uncompressedItems.erase(m_imp->m_uncompressedItems.lower_bound("$;"), |
| m_imp->m_uncompressedItems.end()); |
| |
| m_imp->m_compressedItems.erase(m_imp->m_compressedItems.begin(), |
| m_imp->m_compressedItems.lower_bound("$:")); |
| m_imp->m_compressedItems.erase(m_imp->m_compressedItems.lower_bound("$;"), |
| m_imp->m_compressedItems.end()); |
| |
| m_imp->m_duplicatedItems.erase(m_imp->m_duplicatedItems.begin(), |
| m_imp->m_duplicatedItems.lower_bound("$:")); |
| m_imp->m_duplicatedItems.erase(m_imp->m_duplicatedItems.lower_bound("$;"), |
| m_imp->m_duplicatedItems.end()); |
| |
| |
| |
| std::map<TUINT32, std::string>::iterator it; |
| for (it = m_imp->m_itemHistory.begin(); it != m_imp->m_itemHistory.end();) { |
| if (it->second.size() >= 2 && it->second[0] == '$' && it->second[1] == ':') |
| ++it; |
| else { |
| std::map<TUINT32, std::string>::iterator app = it; |
| app++; |
| m_imp->m_itemHistory.erase(it); |
| it = app; |
| } |
| } |
| |
| std::map<void *, std::string>::iterator jt; |
| for (jt = m_imp->m_itemsByImagePointer.begin(); |
| jt != m_imp->m_itemsByImagePointer.end();) { |
| if (jt->second.size() >= 2 && jt->second[0] == '$' && jt->second[1] == ':') |
| ++jt; |
| else { |
| std::map<void *, std::string>::iterator app = jt; |
| app++; |
| m_imp->m_itemsByImagePointer.erase(jt); |
| jt = app; |
| } |
| } |
| } |
| |
| |
| |
| bool TImageCache::isCached(const std::string &id) const { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| return (m_imp->m_uncompressedItems.find(id) != |
| m_imp->m_uncompressedItems.end() || |
| m_imp->m_compressedItems.find(id) != m_imp->m_compressedItems.end() || |
| m_imp->m_duplicatedItems.find(id) != m_imp->m_duplicatedItems.end()); |
| } |
| |
| |
| #ifdef LEVO |
| |
| bool TImageCache::getSize(const std::string &id, TDimension &size) const { |
| QMutexLocker sl(&m_imp->m_mutex); |
| |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) { |
| UncompressedOnMemoryCacheItemP uncompressed = it->second; |
| assert(uncompressed); |
| TToonzImageP ti = uncompressed->getImage(); |
| if (ti) { |
| size = ti->getSize(); |
| return true; |
| } |
| |
| TRasterImageP ri = uncompressed->getImage(); |
| if (ri && ri->getRaster()) { |
| size = ri->getRaster()->getSize(); |
| return true; |
| } |
| return false; |
| } |
| std::map<std::string, CacheItemP>::iterator itc = |
| m_imp->m_compressedItems.find(id); |
| if (itc == m_imp->m_compressedItems.end()) return false; |
| CacheItemP cacheItem = itc->second; |
| |
| if (cacheItem->m_imageInfo) { |
| RasterImageInfo *rimageInfo = |
| dynamic_cast<RasterImageInfo *>(cacheItem->m_imageInfo); |
| if (rimageInfo) { |
| size = rimageInfo->m_size; |
| return true; |
| } |
| ToonzImageInfo *timageInfo = |
| dynamic_cast<ToonzImageInfo *>(cacheItem->m_imageInfo); |
| if (timageInfo) { |
| size = timageInfo->m_size; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| |
| bool TImageCache::getSavebox(const std::string &id, TRect &savebox) const { |
| QMutexLocker sl(&m_imp->m_mutex); |
| |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) { |
| UncompressedOnMemoryCacheItemP uncompressed = it->second; |
| assert(uncompressed); |
| |
| TToonzImageP ti = uncompressed->getImage(); |
| if (ti) { |
| savebox = ti->getSavebox(); |
| return true; |
| } |
| TRasterImageP ri = uncompressed->getImage(); |
| if (ri) { |
| savebox = ri->getSavebox(); |
| return true; |
| } |
| return false; |
| } |
| std::map<std::string, CacheItemP>::iterator itc = |
| m_imp->m_compressedItems.find(id); |
| if (itc == m_imp->m_compressedItems.end()) return false; |
| |
| CacheItemP cacheItem = itc->second; |
| |
| assert(cacheItem->m_imageInfo); |
| |
| RasterImageInfo *rimageInfo = |
| dynamic_cast<RasterImageInfo *>(cacheItem->m_imageInfo); |
| if (rimageInfo) { |
| savebox = rimageInfo->m_savebox; |
| return true; |
| } |
| #ifndef TNZCORE_LIGHT |
| ToonzImageInfo *timageInfo = |
| dynamic_cast<ToonzImageInfo *>(cacheItem->m_imageInfo); |
| if (timageInfo) { |
| savebox = timageInfo->m_savebox; |
| return true; |
| } |
| #endif |
| return false; |
| } |
| |
| |
| |
| bool TImageCache::getDpi(const std::string &id, double &dpiX, |
| double &dpiY) const { |
| QMutexLocker sl(&m_imp->m_mutex); |
| |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) { |
| UncompressedOnMemoryCacheItemP uncompressed = it->second; |
| assert(uncompressed); |
| TToonzImageP ti = uncompressed->getImage(); |
| if (ti) { |
| ti->getDpi(dpiX, dpiY); |
| return true; |
| } |
| TRasterImageP ri = uncompressed->getImage(); |
| if (ri) { |
| ri->getDpi(dpiX, dpiY); |
| return true; |
| } |
| return false; |
| } |
| std::map<std::string, CacheItemP>::iterator itc = |
| m_imp->m_compressedItems.find(id); |
| if (itc == m_imp->m_compressedItems.end()) return false; |
| CacheItemP cacheItem = itc->second; |
| assert(cacheItem->m_imageInfo); |
| |
| RasterImageInfo *rimageInfo = |
| dynamic_cast<RasterImageInfo *>(cacheItem->m_imageInfo); |
| if (rimageInfo) { |
| dpiX = rimageInfo->m_dpix; |
| dpiY = rimageInfo->m_dpiy; |
| return true; |
| } |
| #ifndef TNZCORE_LIGHT |
| ToonzImageInfo *timageInfo = |
| dynamic_cast<ToonzImageInfo *>(cacheItem->m_imageInfo); |
| if (timageInfo) { |
| dpiX = timageInfo->m_dpix; |
| dpiY = timageInfo->m_dpiy; |
| return true; |
| } |
| #endif |
| return false; |
| } |
| |
| |
| #endif |
| |
| bool TImageCache::getSubsampling(const std::string &id, int &subs) const { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| |
| std::map<std::string, std::string>::iterator it1; |
| if ((it1 = m_imp->m_duplicatedItems.find(id)) != |
| m_imp->m_duplicatedItems.end()) { |
| assert(m_imp->m_duplicatedItems.find(it1->second) == |
| m_imp->m_duplicatedItems.end()); |
| return getSubsampling(it1->second, subs); |
| } |
| |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) { |
| UncompressedOnMemoryCacheItemP uncompressed = it->second; |
| assert(uncompressed); |
| #ifndef TNZCORE_LIGHT |
| if (TToonzImageP ti = uncompressed->getImage()) { |
| subs = ti->getSubsampling(); |
| return true; |
| } |
| |
| else |
| #endif |
| if (TRasterImageP ri = uncompressed->getImage()) { |
| subs = ri->getSubsampling(); |
| return true; |
| } else |
| return false; |
| } |
| std::map<std::string, CacheItemP>::iterator itc = |
| m_imp->m_compressedItems.find(id); |
| if (itc == m_imp->m_compressedItems.end()) return false; |
| CacheItemP cacheItem = itc->second; |
| assert(cacheItem->m_imageInfo); |
| if (RasterImageInfo *rimageInfo = |
| dynamic_cast<RasterImageInfo *>(cacheItem->m_imageInfo)) { |
| subs = rimageInfo->m_subs; |
| return true; |
| } |
| #ifndef TNZCORE_LIGHT |
| else if (ToonzImageInfo *timageInfo = |
| dynamic_cast<ToonzImageInfo *>(cacheItem->m_imageInfo)) { |
| subs = timageInfo->m_subs; |
| return true; |
| } |
| #endif |
| else |
| return false; |
| } |
| |
| |
| |
| bool TImageCache::hasBeenModified(const std::string &id, bool reset) const { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| |
| std::map<std::string, std::string>::iterator it; |
| if ((it = m_imp->m_duplicatedItems.find(id)) != |
| m_imp->m_duplicatedItems.end()) { |
| assert(m_imp->m_duplicatedItems.find(it->second) == |
| m_imp->m_duplicatedItems.end()); |
| return hasBeenModified(it->second, reset); |
| } |
| |
| TImageP img; |
| |
| std::map<std::string, CacheItemP>::iterator itu = |
| m_imp->m_uncompressedItems.find(id); |
| if (itu != m_imp->m_uncompressedItems.end()) { |
| if (reset && itu->second->m_modified) { |
| itu->second->m_modified = false; |
| return true; |
| } else |
| return itu->second->m_modified; |
| } |
| return true; |
| } |
| |
| |
| |
| TImageP TImageCache::get(const std::string &id, bool toBeModified) const { |
| return m_imp->get(id, toBeModified); |
| } |
| |
| |
| |
| TImageP TImageCache::Imp::get(const std::string &id, bool toBeModified) { |
| TThread::MutexLocker sl(&m_mutex); |
| |
| std::map<std::string, std::string>::const_iterator it; |
| if ((it = m_duplicatedItems.find(id)) != m_duplicatedItems.end()) { |
| assert(m_duplicatedItems.find(it->second) == m_duplicatedItems.end()); |
| return get(it->second, toBeModified); |
| } |
| |
| TImageP img; |
| |
| std::map<std::string, CacheItemP>::iterator itu = |
| m_uncompressedItems.find(id); |
| if (itu != m_uncompressedItems.end()) { |
| img = itu->second->getImage(); |
| if (itu->second->m_historyCount != |
| HistoryCount - 1) |
| |
| { |
| assert(m_itemHistory.find(itu->second->m_historyCount) != |
| m_itemHistory.end()); |
| m_itemHistory.erase(itu->second->m_historyCount); |
| m_itemHistory[HistoryCount] = id; |
| itu->second->m_historyCount = HistoryCount; |
| HistoryCount++; |
| } |
| if (toBeModified) { |
| itu->second->m_modified = true; |
| std::map<std::string, CacheItemP>::iterator itc = |
| m_compressedItems.find(id); |
| if (itc != m_compressedItems.end()) m_compressedItems.erase(itc); |
| } |
| return img; |
| } |
| |
| std::map<std::string, CacheItemP>::iterator itc = m_compressedItems.find(id); |
| if (itc == m_compressedItems.end()) return 0; |
| |
| CacheItemP cacheItem = itc->second; |
| |
| img = cacheItem->getImage(); |
| |
| CacheItemP uncompressed; |
| uncompressed = new UncompressedOnMemoryCacheItem(img); |
| m_uncompressedItems[itc->first] = uncompressed; |
| m_itemsByImagePointer[getPointer(img)] = itc->first; |
| |
| m_itemHistory[HistoryCount] = itc->first; |
| uncompressed->m_historyCount = HistoryCount; |
| HistoryCount++; |
| |
| if (CompressedOnMemoryCacheItemP(cacheItem)) |
| |
| |
| { |
| if (10 * cacheItem->getSize() > uncompressed->getSize()) { |
| m_compressedItems.erase(itc); |
| itc = m_compressedItems.end(); |
| } |
| } else |
| assert((CompressedOnDiskCacheItemP)cacheItem || |
| (UncompressedOnDiskCacheItemP)cacheItem); |
| |
| if (toBeModified && itc != m_compressedItems.end()) { |
| uncompressed->m_modified = true; |
| m_compressedItems.erase(itc); |
| } |
| |
| uncompressed->m_cantCompress = toBeModified; |
| |
| doCompress(); |
| |
| uncompressed->m_cantCompress = false; |
| |
| |
| #ifdef DO_MEMCHECK |
| assert(_CrtCheckMemory()); |
| #endif |
| |
| return img; |
| } |
| |
| |
| |
| namespace { |
| |
| class AccumulateMemUsage { |
| public: |
| int operator()(int oldValue, std::pair<std::string, CacheItemP> item) { |
| return oldValue + item.second->getSize(); |
| } |
| }; |
| } |
| |
| UINT TImageCache::getMemUsage() const { |
| TThread::MutexLocker sl(&m_imp->m_mutex); |
| |
| int ret = std::accumulate(m_imp->m_uncompressedItems.begin(), |
| m_imp->m_uncompressedItems.end(), 0, |
| AccumulateMemUsage()); |
| |
| return ret + std::accumulate(m_imp->m_compressedItems.begin(), |
| m_imp->m_compressedItems.end(), 0, |
| AccumulateMemUsage()); |
| } |
| |
| |
| |
| UINT TImageCache::getDiskUsage() const { return 0; } |
| |
| |
| |
| UINT TImageCache::getMemUsage(const std::string &id) const { |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) return it->second->getSize(); |
| |
| it = m_imp->m_compressedItems.find(id); |
| if (it != m_imp->m_compressedItems.end()) return it->second->getSize(); |
| return 0; |
| } |
| |
| |
| |
| |
| |
| UINT TImageCache::getUncompressedMemUsage(const std::string &id) const { |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.find(id); |
| if (it != m_imp->m_uncompressedItems.end()) return it->second->getSize(); |
| |
| it = m_imp->m_compressedItems.find(id); |
| if (it != m_imp->m_compressedItems.end()) return it->second->getSize(); |
| |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| UINT TImageCache::getDiskUsage(const std::string &id) const { return 0; } |
| |
| |
| |
| void TImageCache::dump(std::ostream &os) const { |
| os << "mem: " << getMemUsage() << std::endl; |
| std::map<std::string, CacheItemP>::iterator it = |
| m_imp->m_uncompressedItems.begin(); |
| for (; it != m_imp->m_uncompressedItems.end(); ++it) { |
| os << it->first << std::endl; |
| } |
| } |
| |
| |
| |
| void TImageCache::outputMap(UINT chunkRequested, std::string filename) { |
| m_imp->outputMap(chunkRequested, filename); |
| } |
| |
| |
| |
| void TImageCache::Imp::outputMap(UINT chunkRequested, std::string filename) { |
| TThread::MutexLocker sl(&m_mutex); |
| |
| |
| |
| std::string st = filename + ".txt"; |
| TFilePath fp(st); |
| Tofstream os(fp); |
| |
| int umcount1 = 0; |
| int umcount2 = 0; |
| int umcount3 = 0; |
| int cmcount = 0; |
| int cdcount = 0; |
| int umcount = 0; |
| int udcount = 0; |
| |
| TUINT64 umsize1 = 0; |
| TUINT64 umsize2 = 0; |
| TUINT64 umsize3 = 0; |
| TUINT64 cmsize = 0; |
| TUINT64 cdsize = 0; |
| TUINT64 umsize = 0; |
| TUINT64 udsize = 0; |
| |
| std::map<std::string, CacheItemP>::iterator itu = m_uncompressedItems.begin(); |
| |
| for (; itu != m_uncompressedItems.end(); ++itu) { |
| UncompressedOnMemoryCacheItemP uitem = itu->second; |
| if (uitem->m_image && hasExternalReferences(uitem->m_image)) { |
| umcount1++; |
| umsize1 += (TUINT64)(itu->second->getSize() / 1024.0); |
| } else if (uitem->m_cantCompress) { |
| umcount2++; |
| umsize2 += (TUINT64)(itu->second->getSize() / 1024.0); |
| } else { |
| umcount3++; |
| umsize3 += (TUINT64)(itu->second->getSize() / 1024.0); |
| } |
| } |
| std::map<std::string, CacheItemP>::iterator itc = m_compressedItems.begin(); |
| for (; itc != m_compressedItems.end(); ++itc) { |
| CacheItemP boh = itc->second; |
| CompressedOnMemoryCacheItemP cmitem = itc->second; |
| CompressedOnDiskCacheItemP cditem = itc->second; |
| UncompressedOnDiskCacheItemP uditem = itc->second; |
| if (cmitem) { |
| cmcount++; |
| cmsize += cmitem->getSize(); |
| } else if (cditem) { |
| cdcount++; |
| cdsize += cditem->getSize(); |
| } else { |
| assert(uditem); |
| udcount++; |
| udsize += uditem->getSize(); |
| } |
| } |
| |
| TUINT64 currPhisMemoryAvail = |
| (TUINT64)(TSystem::getFreeMemorySize(true) / 1024.0); |
| |
| |
| os << "************************************************************\n"; |
| |
| os << "***requested memory: " + |
| std::to_string((int)chunkRequested / 1048576.0) + " MB\n"; |
| |
| |
| |
| |
| os << "***phismem " + std::to_string((int)currPhisMemoryAvail) + |
| " MB; percent of tot:" + |
| std::to_string( |
| (int)((currPhisMemoryAvail * 100) / m_reservedMemory)) + |
| "\n"; |
| |
| |
| os << "***uncompressed NOT compressable(refcount>1) " + |
| std::to_string(umcount1) + " " + std::to_string(umsize1 / 1024.0) + |
| " MB\n"; |
| os << "***uncompressed NOT compressable(cantCompress) " + |
| std::to_string(umcount2) + " " + std::to_string(umsize2 / 1024.0) + |
| " MB\n"; |
| os << "***uncompressed compressable " + std::to_string(umcount3) + " " + |
| std::to_string(umsize3 / 1024.0) + " MB\n"; |
| os << "***compressed on mem " + std::to_string(cmcount) + " " + |
| std::to_string((int)cmsize / 1048576.0) + " MB\n"; |
| os << "***compressed on disk " + std::to_string(cdcount) + " " + |
| std::to_string((int)cdsize / 1048576.0) + " MB\n"; |
| os << "***uncompressed on disk " + std::to_string(udcount) + " " + |
| std::to_string((int)udsize / 1048576.0) + " MB\n"; |
| |
| |
| |
| |
| } |
| |
| |
| |
| void TImageCache::compress(const std::string &id) { m_imp->doCompress(id); } |
| |
| |
| |
| #ifndef TNZCORE_LIGHT |
| |
| void TImageCache::add(const QString &id, const TImageP &img, bool overwrite) { |
| if (!isEnabled()) return; |
| m_imp->add(id.toStdString(), img, overwrite); |
| } |
| |
| |
| |
| void TImageCache::remove(const QString &id) { m_imp->remove(id.toStdString()); } |
| |
| |
| |
| TImageP TImageCache::get(const QString &id, bool toBeModified) const { |
| return get(id.toStdString(), toBeModified); |
| } |
| |
| #endif |
| |
| |
| |
| |
| |
| DEFINE_CLASS_CODE(TCachedImage, 103) |
| |
| TCachedImage::TCachedImage() |
| : TSmartObject(m_classCode) |
| , m_ref(TImageCache::instance()->getUniqueId()) {} |
| |
| |
| |
| TCachedImage::TCachedImage(const TImageP &img) |
| : TSmartObject(m_classCode), m_ref(TImageCache::instance()->getUniqueId()) { |
| setImage(img); |
| } |
| |
| |
| |
| TCachedImage::~TCachedImage() { TImageCache::instance()->remove(m_ref); } |
| |
| |
| |
| void TCachedImage::setImage(const TImageP &img, bool overwrite) { |
| TImageCache::instance()->add(m_ref, img, overwrite); |
| } |
| |
| |
| |
| TImageP TCachedImage::image(bool toBeModified) { |
| return TImageCache::instance()->get(m_ref, toBeModified); |
| } |
| |