| 1 | /* |
| 2 | * Texture Filtering |
| 3 | * Version: 1.0 |
| 4 | * |
| 5 | * Copyright (C) 2007 Hiroshi Morii All Rights Reserved. |
| 6 | * Email koolsmoky(at)users.sourceforge.net |
| 7 | * Web http://www.3dfxzone.it/koolsmoky |
| 8 | * |
| 9 | * this is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation; either version 2, or (at your option) |
| 12 | * any later version. |
| 13 | * |
| 14 | * this is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with GNU Make; see the file COPYING. If not, write to |
| 21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 22 | */ |
| 23 | |
| 24 | #ifdef __MSC__ |
| 25 | #pragma warning(disable: 4786) |
| 26 | #endif |
| 27 | |
| 28 | #include <boost/filesystem.hpp> |
| 29 | #include <zlib.h> |
| 30 | #include "TxCache.h" |
| 31 | #include "TxDbg.h" |
| 32 | #include "../Glide64/m64p.h" |
| 33 | #include "../Glide64/Gfx_1.3.h" |
| 34 | |
| 35 | TxCache::~TxCache() |
| 36 | { |
| 37 | /* free memory, clean up, etc */ |
| 38 | clear(); |
| 39 | |
| 40 | delete _txUtil; |
| 41 | } |
| 42 | |
| 43 | TxCache::TxCache(int options, int cachesize, const wchar_t *datapath, |
| 44 | const wchar_t *cachepath, const wchar_t *ident, |
| 45 | dispInfoFuncExt callback) |
| 46 | { |
| 47 | _txUtil = new TxUtil(); |
| 48 | |
| 49 | _options = options; |
| 50 | _cacheSize = cachesize; |
| 51 | _callback = callback; |
| 52 | _totalSize = 0; |
| 53 | |
| 54 | /* save path name */ |
| 55 | if (datapath) |
| 56 | _datapath.assign(datapath); |
| 57 | if (cachepath) |
| 58 | _cachepath.assign(cachepath); |
| 59 | |
| 60 | /* save ROM name */ |
| 61 | if (ident) |
| 62 | _ident.assign(ident); |
| 63 | |
| 64 | /* zlib memory buffers to (de)compress hires textures */ |
| 65 | if (_options & (GZ_TEXCACHE|GZ_HIRESTEXCACHE)) { |
| 66 | _gzdest0 = TxMemBuf::getInstance()->get(0); |
| 67 | _gzdest1 = TxMemBuf::getInstance()->get(1); |
| 68 | _gzdestLen = (TxMemBuf::getInstance()->size_of(0) < TxMemBuf::getInstance()->size_of(1)) ? |
| 69 | TxMemBuf::getInstance()->size_of(0) : TxMemBuf::getInstance()->size_of(1); |
| 70 | |
| 71 | if (!_gzdest0 || !_gzdest1 || !_gzdestLen) { |
| 72 | _options &= ~(GZ_TEXCACHE|GZ_HIRESTEXCACHE); |
| 73 | _gzdest0 = NULL; |
| 74 | _gzdest1 = NULL; |
| 75 | _gzdestLen = 0; |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | boolean |
| 81 | TxCache::add(uint64 checksum, GHQTexInfo *info, int dataSize) |
| 82 | { |
| 83 | /* NOTE: dataSize must be provided if info->data is zlib compressed. */ |
| 84 | |
| 85 | if (!checksum || !info->data) return 0; |
| 86 | |
| 87 | uint8 *dest = info->data; |
| 88 | uint16 format = info->format; |
| 89 | |
| 90 | if (!dataSize) { |
| 91 | dataSize = _txUtil->sizeofTx(info->width, info->height, info->format); |
| 92 | |
| 93 | if (!dataSize) return 0; |
| 94 | |
| 95 | if (_options & (GZ_TEXCACHE|GZ_HIRESTEXCACHE)) { |
| 96 | /* zlib compress it. compression level:1 (best speed) */ |
| 97 | uLongf destLen = _gzdestLen; |
| 98 | dest = (dest == _gzdest0) ? _gzdest1 : _gzdest0; |
| 99 | if (compress2(dest, &destLen, info->data, dataSize, 1) != Z_OK) { |
| 100 | dest = info->data; |
| 101 | DBG_INFO(80, L"Error: zlib compression failed!\n"); |
| 102 | } else { |
| 103 | DBG_INFO(80, L"zlib compressed: %.02fkb->%.02fkb\n", (float)dataSize/1000, (float)destLen/1000); |
| 104 | dataSize = destLen; |
| 105 | format |= GR_TEXFMT_GZ; |
| 106 | } |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | /* if cache size exceeds limit, remove old cache */ |
| 111 | if (_cacheSize > 0) { |
| 112 | _totalSize += dataSize; |
| 113 | if ((_totalSize > _cacheSize) && !_cachelist.empty()) { |
| 114 | /* _cachelist is arranged so that frequently used textures are in the back */ |
| 115 | std::list<uint64>::iterator itList = _cachelist.begin(); |
| 116 | while (itList != _cachelist.end()) { |
| 117 | /* find it in _cache */ |
| 118 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.find(*itList); |
| 119 | if (itMap != _cache.end()) { |
| 120 | /* yep we have it. remove it. */ |
| 121 | _totalSize -= (*itMap).second->size; |
| 122 | free((*itMap).second->info.data); |
| 123 | delete (*itMap).second; |
| 124 | _cache.erase(itMap); |
| 125 | } |
| 126 | itList++; |
| 127 | |
| 128 | /* check if memory cache has enough space */ |
| 129 | if (_totalSize <= _cacheSize) |
| 130 | break; |
| 131 | } |
| 132 | /* remove from _cachelist */ |
| 133 | _cachelist.erase(_cachelist.begin(), itList); |
| 134 | |
| 135 | DBG_INFO(80, L"+++++++++\n"); |
| 136 | } |
| 137 | _totalSize -= dataSize; |
| 138 | } |
| 139 | |
| 140 | /* cache it */ |
| 141 | uint8 *tmpdata = (uint8*)malloc(dataSize); |
| 142 | if (tmpdata) { |
| 143 | TXCACHE *txCache = new TXCACHE; |
| 144 | if (txCache) { |
| 145 | /* we can directly write as we filter, but for now we get away |
| 146 | * with doing memcpy after all the filtering is done. |
| 147 | */ |
| 148 | memcpy(tmpdata, dest, dataSize); |
| 149 | |
| 150 | /* copy it */ |
| 151 | memcpy(&txCache->info, info, sizeof(GHQTexInfo)); |
| 152 | txCache->info.data = tmpdata; |
| 153 | txCache->info.format = format; |
| 154 | txCache->size = dataSize; |
| 155 | |
| 156 | /* add to cache */ |
| 157 | if (_cacheSize > 0) { |
| 158 | _cachelist.push_back(checksum); |
| 159 | txCache->it = --(_cachelist.end()); |
| 160 | } |
| 161 | /* _cache[checksum] = txCache; */ |
| 162 | _cache.insert(std::map<uint64, TXCACHE*>::value_type(checksum, txCache)); |
| 163 | |
| 164 | #ifdef DEBUG |
| 165 | DBG_INFO(80, L"[%5d] added!! crc:%08X %08X %d x %d gfmt:%x total:%.02fmb\n", |
| 166 | _cache.size(), (uint32)(checksum >> 32), (uint32)(checksum & 0xffffffff), |
| 167 | info->width, info->height, info->format, (float)_totalSize/1000000); |
| 168 | |
| 169 | DBG_INFO(80, L"smalllodlog2:%d largelodlog2:%d aspectratiolog2:%d\n", |
| 170 | txCache->info.smallLodLog2, txCache->info.largeLodLog2, txCache->info.aspectRatioLog2); |
| 171 | |
| 172 | if (info->tiles) { |
| 173 | DBG_INFO(80, L"tiles:%d un-tiled size:%d x %d\n", info->tiles, info->untiled_width, info->untiled_height); |
| 174 | } |
| 175 | |
| 176 | if (_cacheSize > 0) { |
| 177 | DBG_INFO(80, L"cache max config:%.02fmb\n", (float)_cacheSize/1000000); |
| 178 | |
| 179 | if (_cache.size() != _cachelist.size()) { |
| 180 | DBG_INFO(80, L"Error: cache/cachelist mismatch! (%d/%d)\n", _cache.size(), _cachelist.size()); |
| 181 | } |
| 182 | } |
| 183 | #endif |
| 184 | |
| 185 | /* total cache size */ |
| 186 | _totalSize += dataSize; |
| 187 | |
| 188 | return 1; |
| 189 | } |
| 190 | free(tmpdata); |
| 191 | } |
| 192 | |
| 193 | return 0; |
| 194 | } |
| 195 | |
| 196 | boolean |
| 197 | TxCache::get(uint64 checksum, GHQTexInfo *info) |
| 198 | { |
| 199 | if (!checksum || _cache.empty()) return 0; |
| 200 | |
| 201 | /* find a match in cache */ |
| 202 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.find(checksum); |
| 203 | if (itMap != _cache.end()) { |
| 204 | /* yep, we've got it. */ |
| 205 | memcpy(info, &(((*itMap).second)->info), sizeof(GHQTexInfo)); |
| 206 | |
| 207 | /* push it to the back of the list */ |
| 208 | if (_cacheSize > 0) { |
| 209 | _cachelist.erase(((*itMap).second)->it); |
| 210 | _cachelist.push_back(checksum); |
| 211 | ((*itMap).second)->it = --(_cachelist.end()); |
| 212 | } |
| 213 | |
| 214 | /* zlib decompress it */ |
| 215 | if (info->format & GR_TEXFMT_GZ) { |
| 216 | uLongf destLen = _gzdestLen; |
| 217 | uint8 *dest = (_gzdest0 == info->data) ? _gzdest1 : _gzdest0; |
| 218 | if (uncompress(dest, &destLen, info->data, ((*itMap).second)->size) != Z_OK) { |
| 219 | DBG_INFO(80, L"Error: zlib decompression failed!\n"); |
| 220 | return 0; |
| 221 | } |
| 222 | info->data = dest; |
| 223 | info->format &= ~GR_TEXFMT_GZ; |
| 224 | DBG_INFO(80, L"zlib decompressed: %.02fkb->%.02fkb\n", (float)(((*itMap).second)->size)/1000, (float)destLen/1000); |
| 225 | } |
| 226 | |
| 227 | return 1; |
| 228 | } |
| 229 | |
| 230 | return 0; |
| 231 | } |
| 232 | |
| 233 | boolean |
| 234 | TxCache::save(const wchar_t *path, const wchar_t *filename, int config) |
| 235 | { |
| 236 | if (!_cache.empty()) { |
| 237 | /* dump cache to disk */ |
| 238 | char cbuf[MAX_PATH]; |
| 239 | |
| 240 | boost::filesystem::wpath cachepath(path); |
| 241 | boost::filesystem::create_directory(cachepath); |
| 242 | |
| 243 | /* Ugly hack to enable fopen/gzopen in Win9x */ |
| 244 | #ifdef BOOST_WINDOWS_API |
| 245 | wchar_t curpath[MAX_PATH]; |
| 246 | GETCWD(MAX_PATH, curpath); |
| 247 | CHDIR(cachepath.wstring().c_str()); |
| 248 | #else |
| 249 | char curpath[MAX_PATH]; |
| 250 | wcstombs(cbuf, cachepath.wstring().c_str(), MAX_PATH); |
| 251 | if (GETCWD(MAX_PATH, curpath) == NULL) |
| 252 | ERRLOG("Error while retrieving working directory!"); |
| 253 | if (CHDIR(cbuf) != 0) |
| 254 | ERRLOG("Error while changing current directory to '%s'!", cbuf); |
| 255 | #endif |
| 256 | |
| 257 | wcstombs(cbuf, filename, MAX_PATH); |
| 258 | |
| 259 | gzFile gzfp = gzopen(cbuf, "wb1"); |
| 260 | DBG_INFO(80, L"gzfp:%x file:%ls\n", gzfp, filename); |
| 261 | if (gzfp) { |
| 262 | /* write header to determine config match */ |
| 263 | gzwrite(gzfp, &config, 4); |
| 264 | |
| 265 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.begin(); |
| 266 | while (itMap != _cache.end()) { |
| 267 | uint8 *dest = (*itMap).second->info.data; |
| 268 | uint32 destLen = (*itMap).second->size; |
| 269 | uint16 format = (*itMap).second->info.format; |
| 270 | |
| 271 | /* to keep things simple, we save the texture data in a zlib uncompressed state. */ |
| 272 | /* sigh... for those who cannot wait the extra few seconds. changed to keep |
| 273 | * texture data in a zlib compressed state. if the GZ_TEXCACHE or GZ_HIRESTEXCACHE |
| 274 | * option is toggled, the cache will need to be rebuilt. |
| 275 | */ |
| 276 | /*if (format & GR_TEXFMT_GZ) { |
| 277 | dest = _gzdest0; |
| 278 | destLen = _gzdestLen; |
| 279 | if (dest && destLen) { |
| 280 | if (uncompress(dest, &destLen, (*itMap).second->info.data, (*itMap).second->size) != Z_OK) { |
| 281 | dest = NULL; |
| 282 | destLen = 0; |
| 283 | } |
| 284 | format &= ~GR_TEXFMT_GZ; |
| 285 | } |
| 286 | }*/ |
| 287 | |
| 288 | if (dest && destLen) { |
| 289 | /* texture checksum */ |
| 290 | gzwrite(gzfp, &((*itMap).first), 8); |
| 291 | |
| 292 | /* other texture info */ |
| 293 | gzwrite(gzfp, &((*itMap).second->info.width), 4); |
| 294 | gzwrite(gzfp, &((*itMap).second->info.height), 4); |
| 295 | gzwrite(gzfp, &format, 2); |
| 296 | |
| 297 | gzwrite(gzfp, &((*itMap).second->info.smallLodLog2), 4); |
| 298 | gzwrite(gzfp, &((*itMap).second->info.largeLodLog2), 4); |
| 299 | gzwrite(gzfp, &((*itMap).second->info.aspectRatioLog2), 4); |
| 300 | |
| 301 | gzwrite(gzfp, &((*itMap).second->info.tiles), 4); |
| 302 | gzwrite(gzfp, &((*itMap).second->info.untiled_width), 4); |
| 303 | gzwrite(gzfp, &((*itMap).second->info.untiled_height), 4); |
| 304 | |
| 305 | gzwrite(gzfp, &((*itMap).second->info.is_hires_tex), 1); |
| 306 | |
| 307 | gzwrite(gzfp, &destLen, 4); |
| 308 | gzwrite(gzfp, dest, destLen); |
| 309 | } |
| 310 | |
| 311 | itMap++; |
| 312 | |
| 313 | /* not ready yet */ |
| 314 | /*if (_callback) |
| 315 | (*_callback)(L"Total textures saved to HDD: %d\n", std::distance(itMap, _cache.begin()));*/ |
| 316 | } |
| 317 | gzclose(gzfp); |
| 318 | } |
| 319 | |
| 320 | if (CHDIR(curpath) != 0) |
| 321 | ERRLOG("Error while changing current directory back to original path of '%s'!", curpath); |
| 322 | } |
| 323 | |
| 324 | return _cache.empty(); |
| 325 | } |
| 326 | |
| 327 | boolean |
| 328 | TxCache::load(const wchar_t *path, const wchar_t *filename, int config) |
| 329 | { |
| 330 | /* find it on disk */ |
| 331 | char cbuf[MAX_PATH]; |
| 332 | |
| 333 | boost::filesystem::wpath cachepath(path); |
| 334 | |
| 335 | #ifdef BOOST_WINDOWS_API |
| 336 | wchar_t curpath[MAX_PATH]; |
| 337 | GETCWD(MAX_PATH, curpath); |
| 338 | CHDIR(cachepath.wstring().c_str()); |
| 339 | #else |
| 340 | char curpath[MAX_PATH]; |
| 341 | wcstombs(cbuf, cachepath.wstring().c_str(), MAX_PATH); |
| 342 | if (GETCWD(MAX_PATH, curpath) == NULL) |
| 343 | ERRLOG("Error while retrieving working directory!"); |
| 344 | if (CHDIR(cbuf) != 0) |
| 345 | ERRLOG("Error while changing current directory to '%s'!", cbuf); |
| 346 | #endif |
| 347 | |
| 348 | wcstombs(cbuf, filename, MAX_PATH); |
| 349 | |
| 350 | gzFile gzfp = gzopen(cbuf, "rb"); |
| 351 | DBG_INFO(80, L"gzfp:%x file:%ls\n", gzfp, filename); |
| 352 | if (gzfp) { |
| 353 | /* yep, we have it. load it into memory cache. */ |
| 354 | int dataSize; |
| 355 | uint64 checksum; |
| 356 | GHQTexInfo tmpInfo; |
| 357 | int tmpconfig; |
| 358 | /* read header to determine config match */ |
| 359 | gzread(gzfp, &tmpconfig, 4); |
| 360 | |
| 361 | if (tmpconfig == config) { |
| 362 | do { |
| 363 | memset(&tmpInfo, 0, sizeof(GHQTexInfo)); |
| 364 | |
| 365 | gzread(gzfp, &checksum, 8); |
| 366 | |
| 367 | gzread(gzfp, &tmpInfo.width, 4); |
| 368 | gzread(gzfp, &tmpInfo.height, 4); |
| 369 | gzread(gzfp, &tmpInfo.format, 2); |
| 370 | |
| 371 | gzread(gzfp, &tmpInfo.smallLodLog2, 4); |
| 372 | gzread(gzfp, &tmpInfo.largeLodLog2, 4); |
| 373 | gzread(gzfp, &tmpInfo.aspectRatioLog2, 4); |
| 374 | |
| 375 | gzread(gzfp, &tmpInfo.tiles, 4); |
| 376 | gzread(gzfp, &tmpInfo.untiled_width, 4); |
| 377 | gzread(gzfp, &tmpInfo.untiled_height, 4); |
| 378 | |
| 379 | gzread(gzfp, &tmpInfo.is_hires_tex, 1); |
| 380 | |
| 381 | gzread(gzfp, &dataSize, 4); |
| 382 | |
| 383 | tmpInfo.data = (uint8*)malloc(dataSize); |
| 384 | if (tmpInfo.data) { |
| 385 | gzread(gzfp, tmpInfo.data, dataSize); |
| 386 | |
| 387 | /* add to memory cache */ |
| 388 | add(checksum, &tmpInfo, (tmpInfo.format & GR_TEXFMT_GZ) ? dataSize : 0); |
| 389 | |
| 390 | free(tmpInfo.data); |
| 391 | } else { |
| 392 | gzseek(gzfp, dataSize, SEEK_CUR); |
| 393 | } |
| 394 | |
| 395 | /* skip in between to prevent the loop from being tied down to vsync */ |
| 396 | if (_callback && (!(_cache.size() % 100) || gzeof(gzfp))) |
| 397 | (*_callback)(L"[%d] total mem:%.02fmb - %ls\n", _cache.size(), (float)_totalSize/1000000, filename); |
| 398 | |
| 399 | } while (!gzeof(gzfp)); |
| 400 | gzclose(gzfp); |
| 401 | } else { |
| 402 | if ((tmpconfig & HIRESTEXTURES_MASK) != (config & HIRESTEXTURES_MASK)) { |
| 403 | const char *conf_str; |
| 404 | if ((tmpconfig & HIRESTEXTURES_MASK) == NO_HIRESTEXTURES) |
| 405 | conf_str = "0"; |
| 406 | else if ((tmpconfig & HIRESTEXTURES_MASK) == RICE_HIRESTEXTURES) |
| 407 | conf_str = "1"; |
| 408 | else |
| 409 | conf_str = "set to an unsupported format"; |
| 410 | |
| 411 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_hirs must be %s", conf_str); |
| 412 | } |
| 413 | if ((tmpconfig & COMPRESS_HIRESTEX) != (config & COMPRESS_HIRESTEX)) |
| 414 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_hirs_cmpr must be %s", (tmpconfig & COMPRESS_HIRESTEX) ? "True" : "False"); |
| 415 | if ((tmpconfig & COMPRESSION_MASK) != (config & COMPRESSION_MASK) && (tmpconfig & COMPRESS_HIRESTEX)) { |
| 416 | const char *conf_str; |
| 417 | if ((tmpconfig & COMPRESSION_MASK) == FXT1_COMPRESSION) |
| 418 | conf_str = "1"; |
| 419 | else if ((tmpconfig & COMPRESSION_MASK) == S3TC_COMPRESSION) |
| 420 | conf_str = "0"; |
| 421 | else |
| 422 | conf_str = "set to an unsupported format"; |
| 423 | |
| 424 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_cmpr must be %s", conf_str); |
| 425 | } |
| 426 | if ((tmpconfig & TILE_HIRESTEX) != (config & TILE_HIRESTEX)) |
| 427 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_hirs_tile must be %s", (tmpconfig & TILE_HIRESTEX) ? "True" : "False"); |
| 428 | if ((tmpconfig & FORCE16BPP_HIRESTEX) != (config & FORCE16BPP_HIRESTEX)) |
| 429 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_hirs_f16bpp must be %s", (tmpconfig & FORCE16BPP_HIRESTEX) ? "True" : "False"); |
| 430 | if ((tmpconfig & GZ_HIRESTEXCACHE) != (config & GZ_HIRESTEXCACHE)) |
| 431 | WriteLog(M64MSG_WARNING, "ghq_hirs_gz must be %s", (tmpconfig & GZ_HIRESTEXCACHE) ? "True" : "False"); |
| 432 | if ((tmpconfig & LET_TEXARTISTS_FLY) != (config & LET_TEXARTISTS_FLY)) |
| 433 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_hirs_let_texartists_fly must be %s", (tmpconfig & LET_TEXARTISTS_FLY) ? "True" : "False"); |
| 434 | |
| 435 | if ((tmpconfig & FILTER_MASK) != (config & FILTER_MASK)) { |
| 436 | const char *conf_str; |
| 437 | if ((tmpconfig & FILTER_MASK) == NO_FILTER) |
| 438 | conf_str = "0"; |
| 439 | else if ((tmpconfig & FILTER_MASK) == SMOOTH_FILTER_1) |
| 440 | conf_str = "1"; |
| 441 | else if ((tmpconfig & FILTER_MASK) == SMOOTH_FILTER_2) |
| 442 | conf_str = "2"; |
| 443 | else if ((tmpconfig & FILTER_MASK) == SMOOTH_FILTER_3) |
| 444 | conf_str = "3"; |
| 445 | else if ((tmpconfig & FILTER_MASK) == SMOOTH_FILTER_4) |
| 446 | conf_str = "4"; |
| 447 | else if ((tmpconfig & FILTER_MASK) == SHARP_FILTER_1) |
| 448 | conf_str = "5"; |
| 449 | else if ((tmpconfig & FILTER_MASK) == SHARP_FILTER_2) |
| 450 | conf_str = "6"; |
| 451 | else |
| 452 | conf_str = "set to an unsupported format"; |
| 453 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_fltr must be %s", conf_str); |
| 454 | } |
| 455 | |
| 456 | if ((tmpconfig & ENHANCEMENT_MASK) != (config & ENHANCEMENT_MASK)) { |
| 457 | const char *conf_str; |
| 458 | if ((tmpconfig & ENHANCEMENT_MASK) == NO_ENHANCEMENT) |
| 459 | conf_str = "0"; |
| 460 | else if ((tmpconfig & ENHANCEMENT_MASK) == X2_ENHANCEMENT) |
| 461 | conf_str = "2"; |
| 462 | else if ((tmpconfig & ENHANCEMENT_MASK) == X2SAI_ENHANCEMENT) |
| 463 | conf_str = "3"; |
| 464 | else if ((tmpconfig & ENHANCEMENT_MASK) == HQ2X_ENHANCEMENT) |
| 465 | conf_str = "4"; |
| 466 | else if ((tmpconfig & ENHANCEMENT_MASK) == HQ2XS_ENHANCEMENT) |
| 467 | conf_str = "5"; |
| 468 | else if ((tmpconfig & ENHANCEMENT_MASK) == LQ2X_ENHANCEMENT) |
| 469 | conf_str = "6"; |
| 470 | else if ((tmpconfig & ENHANCEMENT_MASK) == LQ2XS_ENHANCEMENT) |
| 471 | conf_str = "7"; |
| 472 | else if ((tmpconfig & ENHANCEMENT_MASK) == HQ4X_ENHANCEMENT) |
| 473 | conf_str = "8"; |
| 474 | else |
| 475 | conf_str = "set to an unsupported format"; |
| 476 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_enht must be %s", conf_str); |
| 477 | } |
| 478 | |
| 479 | if ((tmpconfig & COMPRESS_TEX) != (config & COMPRESS_TEX)) |
| 480 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_enht_cmpr must be %s", (tmpconfig & COMPRESS_TEX) ? "True" : "False"); |
| 481 | if ((tmpconfig & FORCE16BPP_TEX) != (config & FORCE16BPP_TEX)) |
| 482 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_enht_f16bpp must be %s", (tmpconfig & FORCE16BPP_TEX) ? "True" : "False"); |
| 483 | if ((tmpconfig & GZ_TEXCACHE) != (config & GZ_TEXCACHE)) |
| 484 | WriteLog(M64MSG_WARNING, "Ignored texture cache due to incompatible setting: ghq_enht_gz must be %s", (tmpconfig & GZ_TEXCACHE) ? "True" : "False"); |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | if (CHDIR(curpath) != 0) |
| 489 | ERRLOG("Error while changing current directory back to original path of '%s'!", curpath); |
| 490 | |
| 491 | return !_cache.empty(); |
| 492 | } |
| 493 | |
| 494 | boolean |
| 495 | TxCache::del(uint64 checksum) |
| 496 | { |
| 497 | if (!checksum || _cache.empty()) return 0; |
| 498 | |
| 499 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.find(checksum); |
| 500 | if (itMap != _cache.end()) { |
| 501 | |
| 502 | /* for texture cache (not hi-res cache) */ |
| 503 | if (!_cachelist.empty()) _cachelist.erase(((*itMap).second)->it); |
| 504 | |
| 505 | /* remove from cache */ |
| 506 | free((*itMap).second->info.data); |
| 507 | _totalSize -= (*itMap).second->size; |
| 508 | delete (*itMap).second; |
| 509 | _cache.erase(itMap); |
| 510 | |
| 511 | DBG_INFO(80, L"removed from cache: checksum = %08X %08X\n", (uint32)(checksum & 0xffffffff), (uint32)(checksum >> 32)); |
| 512 | |
| 513 | return 1; |
| 514 | } |
| 515 | |
| 516 | return 0; |
| 517 | } |
| 518 | |
| 519 | boolean |
| 520 | TxCache::is_cached(uint64 checksum) |
| 521 | { |
| 522 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.find(checksum); |
| 523 | if (itMap != _cache.end()) return 1; |
| 524 | |
| 525 | return 0; |
| 526 | } |
| 527 | |
| 528 | void |
| 529 | TxCache::clear() |
| 530 | { |
| 531 | if (!_cache.empty()) { |
| 532 | std::map<uint64, TXCACHE*>::iterator itMap = _cache.begin(); |
| 533 | while (itMap != _cache.end()) { |
| 534 | free((*itMap).second->info.data); |
| 535 | delete (*itMap).second; |
| 536 | itMap++; |
| 537 | } |
| 538 | _cache.clear(); |
| 539 | } |
| 540 | |
| 541 | if (!_cachelist.empty()) _cachelist.clear(); |
| 542 | |
| 543 | _totalSize = 0; |
| 544 | } |