2002 lines
60 KiB
C++
2002 lines
60 KiB
C++
|
|
|
|
#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"
|
|
#include "tmeshimage.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 "tstopwatch.h"
|
|
#include "tbigmemorymanager.h"
|
|
|
|
#include "tstream.h"
|
|
#include "tenv.h"
|
|
#include <deque>
|
|
#include <numeric>
|
|
#include <sstream>
|
|
#ifdef _WIN32
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
// Qt includes
|
|
#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;
|
|
|
|
// std::ofstream os("C:\\cache.txt");
|
|
|
|
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;
|
|
|
|
// getImage restituisce un'immagine non compressa
|
|
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 && m_compressedRas.getPointer())
|
|
return m_compressedRas->getLx();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
TImageP CompressedOnMemoryCacheItem::getImage() const {
|
|
assert(m_compressedRas);
|
|
|
|
// PER IL MOMENTO DISCRIMINO: DA ELIMINARE
|
|
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;
|
|
// TRaster32P getRaster32() const;
|
|
|
|
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);
|
|
// oss.write((char*)&dataSize, sizeof(TUINT32));
|
|
// assert(!oss.fail());
|
|
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;
|
|
|
|
// is.read((char*)&dataSize, sizeof(TUINT32));
|
|
// assert(unsigned(m_lx*m_ly*m_pixelsize)==dataSize);
|
|
|
|
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() {
|
|
// ATTENZIONE: e' molto piu' veloce se si usa memoria fisica
|
|
// invece che virtuale: la virtuale e' tanta, non c'e' quindi bisogno
|
|
// di comprimere le immagini, che grandi come sono vengono swappate su disco
|
|
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); // compress in the cache
|
|
// till it can nallocate the
|
|
// requested memory
|
|
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; // items ordered by ImageP.getPointer()
|
|
std::map<std::string, std::string> m_duplicatedItems; // for duplicated items
|
|
// (when id1!=id2 but
|
|
// image1==image2) in
|
|
// the map: key is dup
|
|
// id, value is main id
|
|
// memoria fisica totale della macchina che non puo' essere utilizzata;
|
|
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();
|
|
}
|
|
|
|
// Returns true or false whether the image or its eventual raster are
|
|
// referenced by someone other than Toonz cache.
|
|
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; //!!! the TToonzImage::getRaster method increments raster
|
|
//! refCount!(the TRasterImage::getRaster don't)
|
|
}
|
|
#endif
|
|
|
|
return std::max(refCount, img->getRefCount()) > 1;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
void TImageCache::Imp::doCompress() {
|
|
// se la memoria usata per mantenere le immagini decompresse e' superiore
|
|
// a un dato valore, comprimo alcune immagini non compresse non checked-out
|
|
// in modo da liberare memoria
|
|
|
|
// per il momento scorre tutte le immagini alla ricerca di immagini
|
|
// non compresse non checked-out
|
|
|
|
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()); // WARNING the codec buffer allocation can CHANGE
|
|
// the cache.
|
|
item->m_cantCompress = false;
|
|
if (newItem->getSize() ==
|
|
0) /// non c'era memoria sufficiente per il buffer compresso....
|
|
{
|
|
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();
|
|
// doCompress();//restart, since iterators could have been changed (see
|
|
// comment above)
|
|
// return;
|
|
itu = m_itemHistory.begin();
|
|
}
|
|
}
|
|
|
|
// se il quantitativo di memoria utilizzata e' superiore a un dato valore,
|
|
// sposto
|
|
// su disco alcune immagini compresse in modo da liberare memoria
|
|
|
|
if (itu != m_itemHistory.end()) // memory is enough!
|
|
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);
|
|
|
|
// search id in m_uncompressedItems
|
|
std::map<std::string, CacheItemP>::iterator it = m_uncompressedItems.find(id);
|
|
if (it == m_uncompressedItems.end()) return; // id not found: return
|
|
|
|
// is item suitable for compression ?
|
|
CacheItemP item = it->second;
|
|
UncompressedOnMemoryCacheItemP uitem = item;
|
|
if (item->m_cantCompress ||
|
|
(uitem && (!uitem->m_image || hasExternalReferences(uitem->m_image))))
|
|
return;
|
|
|
|
// search id in m_itemHistory
|
|
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; // id not found: return
|
|
|
|
// delete itu from m_itemHistory
|
|
#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
|
|
|
|
// delete item from m_uncompressedItems
|
|
m_uncompressedItems.erase(it);
|
|
|
|
// check if item has been already compressed. this should never happen
|
|
if (m_compressedItems.find(id) != m_compressedItems.end()) return;
|
|
|
|
assert(uitem);
|
|
item->m_cantCompress = true; // ??
|
|
CacheItemP newItem = new CompressedOnMemoryCacheItem(
|
|
item->getImage()); // WARNING the codec buffer allocation can CHANGE the
|
|
// cache.
|
|
item->m_cantCompress = false; // ??
|
|
if (newItem->getSize() ==
|
|
0) /// non c'era memoria sufficiente per il buffer compresso....
|
|
{
|
|
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();
|
|
}
|
|
|
|
/*
|
|
// se il quantitativo di memoria utilizzata e' superiore a un dato valore,
|
|
sposto
|
|
// su disco alcune immagini compresse in modo da liberare memoria
|
|
|
|
if (itu != m_itemHistory.end()) //memory is enough!
|
|
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(toString(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;
|
|
}
|
|
}
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
UCHAR *TImageCache::Imp::compressAndMalloc(TUINT32 size) {
|
|
UCHAR *buf = 0;
|
|
|
|
TThread::MutexLocker sl(&m_mutex);
|
|
|
|
TheCodec::instance()->reset();
|
|
|
|
// if (size!=0)
|
|
// size = size>>10;
|
|
|
|
// assert(size==0 || TBigMemoryManager::instance()->isActive());
|
|
|
|
std::map<TUINT32, std::string>::iterator itu = m_itemHistory.begin();
|
|
while (
|
|
(buf = TBigMemoryManager::instance()->getBuffer(size)) == 0 &&
|
|
itu !=
|
|
m_itemHistory
|
|
.end()) //>TBigMemoryManager::instance()->getAvailableMemoryinKb()))
|
|
{
|
|
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;
|
|
// newItem = new CompressedOnMemoryCacheItem(item->getImage());
|
|
// 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[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;
|
|
/*
|
|
if (!ImageCache::m_instance)
|
|
{
|
|
ImageCache::m_instance = new ImageCache;
|
|
ImageCache::m_destroyer.m_imageCache = ImageCache::m_instance;
|
|
}
|
|
return ImageCache::m_instance;
|
|
*/
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/*
|
|
TFilePath TImageCache::getRootDir() const
|
|
{
|
|
return m_imp->m_rootDir;
|
|
}
|
|
*/
|
|
//------------------------------------------------------------------------------
|
|
|
|
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;
|
|
// m_memUsage -= item->getSize();
|
|
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()) // already present in cache with same id...
|
|
{
|
|
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()) // already present in cache with another id...
|
|
{
|
|
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) || TMeshImageP(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
|
|
// int itemCount =
|
|
// m_imp->m_uncompressedItems.size()+m_imp->m_compressedItems.size();
|
|
// m_imp->outputDebug();
|
|
#endif
|
|
}
|
|
|
|
void TImageCache::remove(const std::string &id) { m_imp->remove(id); }
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void TImageCache::Imp::remove(const std::string &id) {
|
|
if (CacheInstance == 0)
|
|
return; // the remove can be called when exiting from toonz...after the
|
|
// imagecache was already freed!
|
|
|
|
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()) // it's a duplicated id...
|
|
{
|
|
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()) // it has duplicated, so cannot erase it;
|
|
// I erase the duplicate, and assign its
|
|
// id has the main id
|
|
{
|
|
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);
|
|
|
|
// note the ';' - which follows ':' in the ascii table
|
|
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());
|
|
|
|
// Clear maps whose id is on the second of map pairs.
|
|
|
|
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; // not present in cache==modified (for particle purposes...)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
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) // significa che l'ultimo get non era sulla stessa
|
|
// immagine, quindi serve aggiornare l'history!
|
|
{
|
|
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))
|
|
// l'immagine compressa non la tengo insieme alla
|
|
// uncompressa se e' troppo grande
|
|
{
|
|
if (10 * cacheItem->getSize() > uncompressed->getSize()) {
|
|
m_compressedItems.erase(itc);
|
|
itc = m_compressedItems.end();
|
|
}
|
|
} else
|
|
assert((CompressedOnDiskCacheItemP)cacheItem ||
|
|
(UncompressedOnDiskCacheItemP)cacheItem); // deve essere compressa!
|
|
|
|
if (toBeModified && itc != m_compressedItems.end()) {
|
|
uncompressed->m_modified = true;
|
|
m_compressedItems.erase(itc);
|
|
}
|
|
|
|
uncompressed->m_cantCompress = toBeModified;
|
|
// se la memoria utilizzata e' superiore al massimo consentito, comprime
|
|
doCompress();
|
|
|
|
uncompressed->m_cantCompress = false;
|
|
|
|
//#define DO_MEMCHECK
|
|
#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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
//! Returns the uncompressed image size (in KB) of the image associated with
|
|
//! passd id, or 0 if none was found.
|
|
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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
int TImageCache::getItemCount() const
|
|
{
|
|
return m_imp->m_uncompressedItems.size()+m_imp->m_compressedItems.size();
|
|
}
|
|
*/
|
|
//------------------------------------------------------------------------------
|
|
|
|
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);
|
|
//#ifdef _DEBUG
|
|
// static int Count = 0;
|
|
|
|
std::string st = filename /*+toString(Count++)*/ + ".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);
|
|
// TUINT64 currVirtualMemoryAvail = TSystem::getFreeMemorySize(false)/1024.0;
|
|
|
|
os << "************************************************************\n";
|
|
|
|
os << "***requested memory: " +
|
|
std::to_string((int)chunkRequested / 1048576.0) + " MB\n";
|
|
// os<<"*** memory in rasters: " +
|
|
// std::to_string((int)TRaster::getTotalMemoryInKB()/1024.0) + " MB\n";
|
|
// os<<"***virtualmem " + std::to_string((int)currVirtualMemoryAvail) + "
|
|
// MB\n";
|
|
os << "***phismem " + std::to_string((int)currPhisMemoryAvail) +
|
|
" MB; percent of tot:" +
|
|
std::to_string(
|
|
(int)((currPhisMemoryAvail * 100) / m_reservedMemory)) +
|
|
"\n";
|
|
// os<<"***bigmem available" +
|
|
// std::to_string((int)TBigMemoryManager::instance()->getAvailableMemoryinKb());
|
|
os << "***uncompressed NOT compressible(refcount>1) " +
|
|
std::to_string(umcount1) + " " + std::to_string(umsize1 / 1024.0) +
|
|
" MB\n";
|
|
os << "***uncompressed NOT compressible(cantCompress) " +
|
|
std::to_string(umcount2) + " " + std::to_string(umsize2 / 1024.0) +
|
|
" MB\n";
|
|
os << "***uncompressed compressible " + 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";
|
|
|
|
// TBigMemoryManager::instance()->printMap();
|
|
|
|
//#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
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
|
|
|
|
//*************************************************************************************
|
|
// TCachedImage implementation
|
|
//*************************************************************************************
|
|
|
|
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);
|
|
}
|