diff --git a/src/GLideNHQ/TxCache.cpp b/src/GLideNHQ/TxCache.cpp index aebe675b..c5becb65 100644 --- a/src/GLideNHQ/TxCache.cpp +++ b/src/GLideNHQ/TxCache.cpp @@ -25,6 +25,7 @@ #pragma warning(disable: 4786) #endif +#include #include "TxCache.h" #include "TxDbg.h" #include @@ -32,37 +33,60 @@ #include #include -TxCache::~TxCache() +class TxCache::TxCacheImpl { - /* free memory, clean up, etc */ - clear(); -} +public: + TxCacheImpl(const TxCache* pCache, uint64 cacheLimit); -TxCache::TxCache(int options, int cachesize, const wchar_t *cachePath, const wchar_t *ident, - dispInfoFuncExt callback) + bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0); + bool get(Checksum checksum, GHQTexInfo *info); + + bool save(const wchar_t *path, const wchar_t *filename, const int config); + bool load(const wchar_t *path, const wchar_t *filename, const int config, boolean force); + bool del(Checksum checksum); + bool isCached(Checksum checksum); + void clear(); + bool empty() const { return _cache.empty(); } + + uint64 size() const { return _cache.size(); } + uint64 totalSize() const { return _totalSize; } + uint64 cacheLimit() const { return _cacheLimit; } + +private: + struct TXCACHE { + int size; + GHQTexInfo info; + std::list::iterator it; + }; + + std::map _cache; + std::list _cachelist; + + uint8 *_gzdest0; + uint8 *_gzdest1; + uint32 _gzdestLen; + + uint64 _totalSize; + uint64 _cacheLimit; + +private: + const TxCache* _pTxCache; +}; + +TxCache::TxCacheImpl::TxCacheImpl(const TxCache* pCache, uint64 cacheLimit) + : _pTxCache(pCache) + , _cacheLimit(cacheLimit) + , _totalSize(0U) { - _options = options; - _cacheSize = cachesize; - _callback = callback; - _totalSize = 0; - - /* save path name */ - if (cachePath) - _cachePath.assign(cachePath); - - /* save ROM name */ - if (ident) - _ident.assign(ident); - /* zlib memory buffers to (de)compress hires textures */ - if (_options & (GZ_TEXCACHE|GZ_HIRESTEXCACHE)) { - _gzdest0 = TxMemBuf::getInstance()->get(0); - _gzdest1 = TxMemBuf::getInstance()->get(1); + if (_pTxCache->_options & (GZ_TEXCACHE | GZ_HIRESTEXCACHE)) { + _gzdest0 = TxMemBuf::getInstance()->get(0); + _gzdest1 = TxMemBuf::getInstance()->get(1); _gzdestLen = (TxMemBuf::getInstance()->size_of(0) < TxMemBuf::getInstance()->size_of(1)) ? - TxMemBuf::getInstance()->size_of(0) : TxMemBuf::getInstance()->size_of(1); + TxMemBuf::getInstance()->size_of(0) : TxMemBuf::getInstance()->size_of(1); if (!_gzdest0 || !_gzdest1 || !_gzdestLen) { - _options &= ~(GZ_TEXCACHE|GZ_HIRESTEXCACHE); + _pTxCache->_options &= ~(GZ_TEXCACHE | GZ_HIRESTEXCACHE); _gzdest0 = nullptr; _gzdest1 = nullptr; _gzdestLen = 0; @@ -70,13 +94,12 @@ TxCache::TxCache(int options, int cachesize, const wchar_t *cachePath, const wch } } -boolean -TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) +bool TxCache::TxCacheImpl::add(Checksum checksum, GHQTexInfo *info, int dataSize) { /* NOTE: dataSize must be provided if info->data is zlib compressed. */ if (!checksum || !info->data || _cache.find(checksum) != _cache.end()) - return 0; + return false; uint8 *dest = info->data; uint32 format = info->format; @@ -85,27 +108,29 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) dataSize = TxUtil::sizeofTx(info->width, info->height, info->format); if (!dataSize) - return 0; + return false; - if (_options & (GZ_TEXCACHE|GZ_HIRESTEXCACHE)) { + if (_pTxCache->_options & (GZ_TEXCACHE | GZ_HIRESTEXCACHE)) { /* zlib compress it. compression level:1 (best speed) */ uLongf destLen = _gzdestLen; dest = (dest == _gzdest0) ? _gzdest1 : _gzdest0; if (compress2(dest, &destLen, info->data, dataSize, 1) != Z_OK) { dest = info->data; DBG_INFO(80, wst("Error: zlib compression failed!\n")); - } else { - DBG_INFO(80, wst("zlib compressed: %.02fkb->%.02fkb\n"), (float)dataSize/1000, (float)destLen/1000); + } + else { + DBG_INFO(80, wst("zlib compressed: %.02fkb->%.02fkb\n"), (float)dataSize / 1000, (float)destLen / 1000); dataSize = destLen; format |= GL_TEXFMT_GZ; } } } - /* if cache size exceeds limit, remove old cache */ - if (_cacheSize > 0) { + + /* if cache size exceeds limit, remove old cache */ + if (_cacheLimit != 0) { _totalSize += dataSize; - if ((_totalSize > _cacheSize) && !_cachelist.empty()) { + if ((_totalSize > _cacheLimit) && !_cachelist.empty()) { /* _cachelist is arranged so that frequently used textures are in the back */ std::list::iterator itList = _cachelist.begin(); while (itList != _cachelist.end()) { @@ -121,7 +146,7 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) itList++; /* check if memory cache has enough space */ - if (_totalSize <= _cacheSize) + if (_totalSize <= _cacheLimit) break; } /* remove from _cachelist */ @@ -135,7 +160,7 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) /* cache it */ uint8 *tmpdata = (uint8*)malloc(dataSize); if (tmpdata == nullptr) - return 0; + return false; TXCACHE *txCache = new TXCACHE; /* we can directly write as we filter, but for now we get away @@ -150,7 +175,7 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) txCache->size = dataSize; /* add to cache */ - if (_cacheSize > 0) { + if (_cacheLimit != 0) { _cachelist.push_back(checksum); txCache->it = --(_cachelist.end()); } @@ -159,11 +184,11 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) #ifdef DEBUG DBG_INFO(80, wst("[%5d] added!! crc:%08X %08X %d x %d gfmt:%x total:%.02fmb\n"), - _cache.size(), (uint32)(checksum >> 32), (uint32)(checksum & 0xffffffff), - info->width, info->height, info->format & 0xffff, (float)_totalSize / 1000000); + _cache.size(), checksum._hi, checksum._low, + info->width, info->height, info->format & 0xffff, (double)_totalSize / 1000000); - if (_cacheSize > 0) { - DBG_INFO(80, wst("cache max config:%.02fmb\n"), (float)_cacheSize / 1000000); + if (_cacheLimit != 0) { + DBG_INFO(80, wst("cache max config:%.02fmb\n"), (double)_cacheLimit / 1000000); if (_cache.size() != _cachelist.size()) { DBG_INFO(80, wst("Error: cache/cachelist mismatch! (%d/%d)\n"), _cache.size(), _cachelist.size()); @@ -174,13 +199,13 @@ TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) /* total cache size */ _totalSize += dataSize; - return 1; + return true; } -boolean -TxCache::get(uint64 checksum, GHQTexInfo *info) +bool TxCache::TxCacheImpl::get(Checksum checksum, GHQTexInfo *info) { - if (!checksum || _cache.empty()) return 0; + if (!checksum || _cache.empty()) + return false; /* find a match in cache */ auto itMap = _cache.find(checksum); @@ -189,7 +214,7 @@ TxCache::get(uint64 checksum, GHQTexInfo *info) memcpy(info, &(((*itMap).second)->info), sizeof(GHQTexInfo)); /* push it to the back of the list */ - if (_cacheSize > 0) { + if (_cacheLimit != 0) { _cachelist.erase(((*itMap).second)->it); _cachelist.push_back(checksum); ((*itMap).second)->it = --(_cachelist.end()); @@ -201,24 +226,23 @@ TxCache::get(uint64 checksum, GHQTexInfo *info) uint8 *dest = (_gzdest0 == info->data) ? _gzdest1 : _gzdest0; if (uncompress(dest, &destLen, info->data, ((*itMap).second)->size) != Z_OK) { DBG_INFO(80, wst("Error: zlib decompression failed!\n")); - return 0; + return false; } info->data = dest; info->format &= ~GL_TEXFMT_GZ; - DBG_INFO(80, wst("zlib decompressed: %.02fkb->%.02fkb\n"), (float)(((*itMap).second)->size)/1000, (float)destLen/1000); + DBG_INFO(80, wst("zlib decompressed: %.02fkb->%.02fkb\n"), (float)(((*itMap).second)->size) / 1000, (float)destLen / 1000); } - return 1; + return true; } - return 0; + return false; } -boolean -TxCache::save(const wchar_t *path, const wchar_t *filename, int config) +bool TxCache::TxCacheImpl::save(const wchar_t *path, const wchar_t *filename, int config) { if (_cache.empty()) - return 0; + return false; /* dump cache to disk */ char cbuf[MAX_PATH]; @@ -254,20 +278,20 @@ TxCache::save(const wchar_t *path, const wchar_t *filename, int config) /* to keep things simple, we save the texture data in a zlib uncompressed state. */ /* sigh... for those who cannot wait the extra few seconds. changed to keep - * texture data in a zlib compressed state. if the GZ_TEXCACHE or GZ_HIRESTEXCACHE - * option is toggled, the cache will need to be rebuilt. - */ + * texture data in a zlib compressed state. if the GZ_TEXCACHE or GZ_HIRESTEXCACHE + * option is toggled, the cache will need to be rebuilt. + */ /*if (format & GL_TEXFMT_GZ) { - dest = _gzdest0; - destLen = _gzdestLen; - if (dest && destLen) { - if (uncompress(dest, &destLen, (*itMap).second->info.data, (*itMap).second->size) != Z_OK) { - dest = nullptr; - destLen = 0; - } - format &= ~GL_TEXFMT_GZ; - } - }*/ + dest = _gzdest0; + destLen = _gzdestLen; + if (dest && destLen) { + if (uncompress(dest, &destLen, (*itMap).second->info.data, (*itMap).second->size) != Z_OK) { + dest = nullptr; + destLen = 0; + } + format &= ~GL_TEXFMT_GZ; + } + }*/ if (dest && destLen) { /* texture checksum */ @@ -287,19 +311,18 @@ TxCache::save(const wchar_t *path, const wchar_t *filename, int config) itMap++; - if (_callback) - (*_callback)(wst("Total textures saved to HDD: %d\n"), ++total); + if (_pTxCache->_callback) + (*_pTxCache->_callback)(wst("Total textures saved to HDD: %d\n"), ++total); } gzclose(gzfp); } CHDIR(curpath); - return _cache.empty() ? 0 : 1; + return !_cache.empty(); } -boolean -TxCache::load(const wchar_t *path, const wchar_t *filename, int config, boolean force) +bool TxCache::TxCacheImpl::load(const wchar_t *path, const wchar_t *filename, int config, boolean force) { /* find it on disk */ char cbuf[MAX_PATH]; @@ -350,13 +373,14 @@ TxCache::load(const wchar_t *path, const wchar_t *filename, int config, boolean add(checksum, &tmpInfo, (tmpInfo.format & GL_TEXFMT_GZ) ? dataSize : 0); free(tmpInfo.data); - } else { + } + else { gzseek(gzfp, dataSize, SEEK_CUR); } /* skip in between to prevent the loop from being tied down to vsync */ - if (_callback && (!(_cache.size() % 100) || gzeof(gzfp))) - (*_callback)(wst("[%d] total mem:%.02fmb - %ls\n"), _cache.size(), (float)_totalSize/1000000, filename); + if (_pTxCache->_callback && (!(_cache.size() % 100) || gzeof(gzfp))) + (*_pTxCache->_callback)(wst("[%d] total mem:%.02fmb - %ls\n"), _cache.size(), (float)_totalSize / 1000000, filename); } while (!gzeof(gzfp)); gzclose(gzfp); @@ -368,16 +392,17 @@ TxCache::load(const wchar_t *path, const wchar_t *filename, int config, boolean return !_cache.empty(); } -boolean -TxCache::del(uint64 checksum) +bool TxCache::TxCacheImpl::del(Checksum checksum) { - if (!checksum || _cache.empty()) return 0; + if (!checksum || _cache.empty()) + return false; auto itMap = _cache.find(checksum); if (itMap != _cache.end()) { /* for texture cache (not hi-res cache) */ - if (!_cachelist.empty()) _cachelist.erase(((*itMap).second)->it); + if (!_cachelist.empty()) + _cachelist.erase(((*itMap).second)->it); /* remove from cache */ free((*itMap).second->info.data); @@ -385,25 +410,20 @@ TxCache::del(uint64 checksum) delete (*itMap).second; _cache.erase(itMap); - DBG_INFO(80, wst("removed from cache: checksum = %08X %08X\n"), (uint32)(checksum & 0xffffffff), (uint32)(checksum >> 32)); + DBG_INFO(80, wst("removed from cache: checksum = %08X %08X\n"), checksum._low, checksum._hi); - return 1; + return true; } - return 0; + return false; } -boolean -TxCache::is_cached(uint64 checksum) +bool TxCache::TxCacheImpl::isCached(Checksum checksum) { - auto itMap = _cache.find(checksum); - if (itMap != _cache.end()) return 1; - - return 0; + return _cache.find(checksum) != _cache.end(); } -void -TxCache::clear() +void TxCache::TxCacheImpl::clear() { if (!_cache.empty()) { auto itMap = _cache.begin(); @@ -419,3 +439,83 @@ TxCache::clear() _totalSize = 0; } + +TxCache::~TxCache() +{ + /* free memory, clean up, etc */ + clear(); +} + +TxCache::TxCache(uint32 options, + uint64 cachesize, + const wchar_t *cachePath, + const wchar_t *ident, + dispInfoFuncExt callback) + : _options(options) + , _callback(callback) +{ + /* save path name */ + if (cachePath) + _cachePath.assign(cachePath); + + /* save ROM name */ + if (ident) + _ident.assign(ident); + + _pImpl.reset(new TxCacheImpl(this, cachesize)); +} + +bool TxCache::add(Checksum checksum, GHQTexInfo *info, int dataSize) +{ + return _pImpl->add(checksum, info, dataSize); +} + +bool TxCache::get(Checksum checksum, GHQTexInfo *info) +{ + return _pImpl->get(checksum, info); +} + +uint64 TxCache::size() const +{ + return _pImpl->size(); +} + +uint64 TxCache::totalSize() const +{ + return _pImpl->totalSize(); +} + +uint64 TxCache::cacheLimit() const +{ + return _pImpl->cacheLimit(); +} + +boolean TxCache::save(const wchar_t *path, const wchar_t *filename, const int config) +{ + return _pImpl->save(path, filename, config); +} + +boolean TxCache::load(const wchar_t *path, const wchar_t *filename, const int config, boolean force) +{ + return _pImpl->load(path, filename, config, force); +} + +boolean TxCache::del(Checksum checksum) +{ + return _pImpl->del(checksum); +} + +boolean TxCache::isCached(Checksum checksum) +{ + return _pImpl->isCached(checksum); +} + +void TxCache::clear() +{ + _pImpl->clear(); +} + +bool TxCache::empty() const +{ + return _pImpl->empty(); +} diff --git a/src/GLideNHQ/TxCache.h b/src/GLideNHQ/TxCache.h index d8a0bcfb..d3620bc4 100644 --- a/src/GLideNHQ/TxCache.h +++ b/src/GLideNHQ/TxCache.h @@ -24,44 +24,65 @@ #ifndef __TXCACHE_H__ #define __TXCACHE_H__ -#include "TxInternal.h" -#include "TxUtil.h" #include #include +#include + +#include "TxInternal.h" +#include "TxUtil.h" + +struct Checksum +{ + union + { + uint64 _checksum; /* checksum hi:palette low:texture */ + struct + { + uint32 _low; + uint32 _hi; + }; + }; + + Checksum(uint64 checksum) : _checksum(checksum) {} + operator bool() { + return _checksum != 0; + } + operator uint64() { + return _checksum; + } +}; + +//class TxCacheImpl; class TxCache { private: - std::list _cachelist; - uint8 *_gzdest0; - uint8 *_gzdest1; - uint32 _gzdestLen; + class TxCacheImpl; + friend class TxCacheImpl; + std::unique_ptr _pImpl; + protected: - int _options; - tx_wstring _ident; - tx_wstring _cachePath; - dispInfoFuncExt _callback; - struct TXCACHE { - int size; - GHQTexInfo info; - std::list::iterator it; - }; - int _totalSize; - int _cacheSize; - std::map _cache; - boolean save(const wchar_t *path, const wchar_t *filename, const int config); - boolean load(const wchar_t *path, const wchar_t *filename, const int config, boolean force); - boolean del(uint64 checksum); /* checksum hi:palette low:texture */ - boolean is_cached(uint64 checksum); /* checksum hi:palette low:texture */ - void clear(); + mutable uint32 _options; + tx_wstring _ident; + tx_wstring _cachePath; + dispInfoFuncExt _callback; + + boolean save(const wchar_t *path, const wchar_t *filename, const int config); + boolean load(const wchar_t *path, const wchar_t *filename, const int config, boolean force); + boolean del(Checksum checksum); /* checksum hi:palette low:texture */ + boolean isCached(Checksum checksum); /* checksum hi:palette low:texture */ + void clear(); + uint64 size() const; // number of elements + uint64 totalSize() const; // size of elements in bytes + uint64 cacheLimit() const; + public: - ~TxCache(); - TxCache(int options, int cachesize, const wchar_t *cachePath, const wchar_t *ident, - dispInfoFuncExt callback); - boolean add(uint64 checksum, /* checksum hi:palette low:texture */ - GHQTexInfo *info, int dataSize = 0); - boolean get(uint64 checksum, /* checksum hi:palette low:texture */ - GHQTexInfo *info); + ~TxCache(); + TxCache(uint32 options, uint64 cacheLimit, const wchar_t *cachePath, const wchar_t *ident, + dispInfoFuncExt callback); + bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0); + bool get(Checksum checksum, GHQTexInfo *info); + bool empty() const; }; #endif /* __TXCACHE_H__ */ diff --git a/src/GLideNHQ/TxHiResCache.cpp b/src/GLideNHQ/TxHiResCache.cpp index 51395011..85a3e74e 100644 --- a/src/GLideNHQ/TxHiResCache.cpp +++ b/src/GLideNHQ/TxHiResCache.cpp @@ -120,11 +120,6 @@ boolean TxHiResCache::_HiResTexPackPathExists() const return osal_path_existsW(dir_path.c_str()); } -boolean TxHiResCache::empty() -{ - return _cache.empty(); -} - boolean TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial */ { if (_texPackPath.empty() || _ident.empty()) @@ -154,7 +149,7 @@ boolean TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial * if (res == resError) { if (_callback) (*_callback)(wst("Texture pack load failed. Clear hiresolution texture cache.\n")); INFO(80, wst("Texture pack load failed. Clear hiresolution texture cache.\n")); - _cache.clear(); + clear(); } return res == resOk ? 1 : 0; } @@ -311,7 +306,7 @@ TxHiResCache::loadHiResTextures(const wchar_t * dir_path, boolean replace) uint64 chksum64 = (uint64)palchksum; chksum64 <<= 32; chksum64 |= (uint64)chksum; - if (TxCache::is_cached(chksum64)) { + if (isCached(chksum64)) { #if !DEBUG INFO(80, wst("-----\n")); INFO(80, wst("path: %ls\n"), dir_path.string().c_str()); @@ -740,7 +735,7 @@ TxHiResCache::loadHiResTextures(const wchar_t * dir_path, boolean replace) if (_callback) { wchar_t tmpbuf[MAX_PATH]; mbstowcs(tmpbuf, fname, MAX_PATH); - (*_callback)(wst("[%d] total mem:%.2fmb - %ls\n"), _cache.size(), (float)_totalSize/1000000, tmpbuf); + (*_callback)(wst("[%d] total mem:%.2fmb - %ls\n"), size(), (totalSize()/1024)/1024.0, tmpbuf); } DBG_INFO(80, wst("texture loaded!\n")); } else { diff --git a/src/GLideNHQ/TxHiResCache.h b/src/GLideNHQ/TxHiResCache.h index 19c9c596..6d4259b0 100644 --- a/src/GLideNHQ/TxHiResCache.h +++ b/src/GLideNHQ/TxHiResCache.h @@ -67,7 +67,6 @@ public: const wchar_t *texPackPath, const wchar_t *ident, dispInfoFuncExt callback); - boolean empty(); boolean load(boolean replace); void dump(); }; diff --git a/src/GLideNHQ/TxTexCache.cpp b/src/GLideNHQ/TxTexCache.cpp index ab86bd05..9b770ab7 100644 --- a/src/GLideNHQ/TxTexCache.cpp +++ b/src/GLideNHQ/TxTexCache.cpp @@ -39,7 +39,7 @@ TxTexCache::TxTexCache(int options, int cachesize, const wchar_t *cachePath, con ) : TxCache((options & ~GZ_HIRESTEXCACHE), cachesize, cachePath, ident, callback) { /* assert local options */ - if (_cachePath.empty() || _ident.empty() || !_cacheSize) + if (_cachePath.empty() || _ident.empty()) _options &= ~DUMP_TEXCACHE; _cacheDumped = 0; @@ -53,9 +53,6 @@ TxTexCache::TxTexCache(int options, int cachesize, const wchar_t *cachePath, con boolean TxTexCache::add(uint64 checksum, GHQTexInfo *info) { - if (_cacheSize <= 0) - return 0; - const boolean res = TxCache::add(checksum, info); if (res) _cacheDumped = 0;