1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-06-27 23:14:05 +00:00

Add support for HD textures, which have the same checksum but different format or size.

See #2569 for details.
This commit is contained in:
Sergey Lipskiy 2022-01-22 16:27:42 +07:00
parent 555fbac213
commit 58faa2874a
15 changed files with 318 additions and 171 deletions

View File

@ -37,17 +37,19 @@
#include "TxCache.h"
#include "TxDbg.h"
#define TXCACHE_FORMAT_VERSION UNDEFINED_1
class TxCacheImpl
{
public:
virtual ~TxCacheImpl() = default;
virtual bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) = 0;
virtual bool get(Checksum checksum, GHQTexInfo *info) = 0;
virtual bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) = 0;
virtual bool save(const wchar_t *path, const wchar_t *filename, const int config) = 0;
virtual bool load(const wchar_t *path, const wchar_t *filename, const int config, bool force) = 0;
virtual bool del(Checksum checksum) = 0;
virtual bool isCached(Checksum checksum) = 0;
virtual bool isCached(Checksum checksum, N64FormatSize n64FmtSz) const = 0;
virtual void clear() = 0;
virtual bool empty() const = 0;
virtual uint32 getOptions() const = 0;
@ -68,12 +70,12 @@ public:
~TxMemoryCache();
bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override;
bool get(Checksum checksum, GHQTexInfo *info) override;
bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) override;
bool save(const wchar_t *path, const wchar_t *filename, const int config) override;
bool load(const wchar_t *path, const wchar_t *filename, const int config, bool force) override;
bool del(Checksum checksum) override;
bool isCached(Checksum checksum) override;
bool isCached(Checksum checksum, N64FormatSize n64FmtSz) const override;
void clear() override;
bool empty() const override { return _cache.empty(); }
@ -95,12 +97,15 @@ private:
uint64 _cacheLimit;
uint64 _totalSize;
std::map<uint64, TXCACHE*> _cache;
using Cache = std::multimap<uint64, TXCACHE*>;
Cache _cache;
Cache::const_iterator find(Checksum checksum, N64FormatSize n64FmtSz) const;
std::list<uint64> _cachelist;
uint8 *_gzdest0 = nullptr;
uint8 *_gzdest1 = nullptr;
uint32 _gzdestLen = 0;
bool _isOldVersion = false;
};
TxMemoryCache::TxMemoryCache(uint32 options,
@ -133,11 +138,11 @@ TxMemoryCache::~TxMemoryCache()
clear();
}
bool TxMemoryCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
bool TxMemoryCache::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())
if (!checksum || !info->data || find(checksum, info->n64_format_size) != _cache.end())
return false;
uint8 *dest = info->data;
@ -206,7 +211,7 @@ bool TxMemoryCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
memcpy(tmpdata, dest, dataSize);
/* copy it */
memcpy(&txCache->info, info, sizeof(GHQTexInfo));
txCache->info = *info;
txCache->info.data = tmpdata;
txCache->info.format = format;
txCache->size = dataSize;
@ -221,7 +226,7 @@ bool TxMemoryCache::add(Checksum 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(), checksum._hi, checksum._low,
_cache.size(), checksum._palette, checksum._texture,
info->width, info->height, info->format & 0xffff, (double)_totalSize / 1000000);
if (_cacheLimit != 0) {
@ -239,41 +244,53 @@ bool TxMemoryCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
return true;
}
bool TxMemoryCache::get(Checksum checksum, GHQTexInfo *info)
TxMemoryCache::Cache::const_iterator TxMemoryCache::find(Checksum checksum, N64FormatSize n64FmtSz) const
{
if (_isOldVersion)
return _cache.find(checksum);
auto range = _cache.equal_range(checksum);
for (auto it = range.first; it != range.second; ++it) {
if (it->second->info.n64_format_size.formatsize() == n64FmtSz.formatsize())
return it;
}
return _cache.cend();
}
bool TxMemoryCache::get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
if (!checksum || _cache.empty())
return false;
/* find a match in cache */
auto itMap = _cache.find(checksum);
if (itMap != _cache.end()) {
/* yep, we've got it. */
memcpy(info, &(((*itMap).second)->info), sizeof(GHQTexInfo));
auto itMap = find(checksum, n64FmtSz);
if (itMap == _cache.end())
return false;
/* push it to the back of the list */
if (_cacheLimit != 0) {
_cachelist.erase(((*itMap).second)->it);
_cachelist.push_back(checksum);
((*itMap).second)->it = --(_cachelist.end());
}
/* yep, we've got it. */
*info = ((*itMap).second)->info;
/* zlib decompress it */
if (info->format & GL_TEXFMT_GZ) {
uLongf destLen = _gzdestLen;
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 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);
}
return true;
/* push it to the back of the list */
if (_cacheLimit != 0) {
_cachelist.erase(((*itMap).second)->it);
_cachelist.push_back(checksum);
((*itMap).second)->it = --(_cachelist.end());
}
return false;
/* zlib decompress it */
if (info->format & GL_TEXFMT_GZ) {
uLongf destLen = _gzdestLen;
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 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);
}
return true;
}
bool TxMemoryCache::save(const wchar_t *path, const wchar_t *filename, int config)
@ -302,6 +319,10 @@ bool TxMemoryCache::save(const wchar_t *path, const wchar_t *filename, int confi
gzFile gzfp = gzopen(cbuf, "wb1");
DBG_INFO(80, wst("gzfp:%x file:%ls\n"), gzfp, filename);
if (gzfp) {
/* write current version */
int version = TXCACHE_FORMAT_VERSION;
gzwrite(gzfp, &version, 4);
/* write header to determine config match */
gzwrite(gzfp, &config, 4);
@ -340,6 +361,7 @@ bool TxMemoryCache::save(const wchar_t *path, const wchar_t *filename, int confi
gzwrite(gzfp, &((*itMap).second->info.texture_format), 2);
gzwrite(gzfp, &((*itMap).second->info.pixel_type), 2);
gzwrite(gzfp, &((*itMap).second->info.is_hires_tex), 1);
gzwrite(gzfp, &((*itMap).second->info.n64_format_size._formatsize), 2);
gzwrite(gzfp, &destLen, 4);
gzwrite(gzfp, dest, destLen);
@ -382,9 +404,19 @@ bool TxMemoryCache::load(const wchar_t *path, const wchar_t *filename, int confi
/* yep, we have it. load it into memory cache. */
int dataSize;
uint64 checksum;
int tmpconfig;
/* read header to determine config match */
gzread(gzfp, &tmpconfig, 4);
int version = 0;
int tmpconfig = 0;
/* read version */
gzread(gzfp, &version, 4);
if (version == TXCACHE_FORMAT_VERSION) {
_isOldVersion = false;
/* read header to determine config match */
gzread(gzfp, &tmpconfig, 4);
} else {
_isOldVersion = true;
tmpconfig = version;
}
if (tmpconfig == config || force) {
do {
@ -398,6 +430,8 @@ bool TxMemoryCache::load(const wchar_t *path, const wchar_t *filename, int confi
gzread(gzfp, &tmpInfo.texture_format, 2);
gzread(gzfp, &tmpInfo.pixel_type, 2);
gzread(gzfp, &tmpInfo.is_hires_tex, 1);
if (!_isOldVersion)
gzread(gzfp, &tmpInfo.n64_format_size._formatsize, 2);
gzread(gzfp, &dataSize, 4);
@ -445,7 +479,7 @@ bool TxMemoryCache::del(Checksum checksum)
delete (*itMap).second;
_cache.erase(itMap);
DBG_INFO(80, wst("removed from cache: checksum = %08X %08X\n"), checksum._low, checksum._hi);
DBG_INFO(80, wst("removed from cache: checksum = %08X %08X\n"), checksum._palette, checksum._texture);
return true;
}
@ -453,9 +487,9 @@ bool TxMemoryCache::del(Checksum checksum)
return false;
}
bool TxMemoryCache::isCached(Checksum checksum)
bool TxMemoryCache::isCached(Checksum checksum, N64FormatSize n64FmtSz) const
{
return _cache.find(checksum) != _cache.end();
return find(checksum, n64FmtSz) != _cache.cend();
}
void TxMemoryCache::clear()
@ -485,12 +519,12 @@ public:
~TxFileStorage() = default;
bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override;
bool get(Checksum checksum, GHQTexInfo *info) override;
bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) override;
bool save(const wchar_t *path, const wchar_t *filename, const int config) override;
bool load(const wchar_t *path, const wchar_t *filename, const int config, bool force) override;
bool del(Checksum checksum) override { return false; }
bool isCached(Checksum checksum) override;
bool isCached(Checksum checksum, N64FormatSize n64FmtSz) const override;
void clear() override;
bool empty() const override { return _storage.empty(); }
@ -513,8 +547,19 @@ private:
dispInfoFuncExt _callback;
uint64 _totalSize = 0;
using StorageMap = std::unordered_map<uint64, int64>;
union StorageOffset
{
StorageOffset() : _data(0U) {}
StorageOffset(int64 data) : _data(data) {}
struct {
int64 _offset : 48;
int64 _formatsize : 16;
};
int64 _data;
};
using StorageMap = std::unordered_multimap<uint64, StorageOffset>;
StorageMap _storage;
StorageMap::const_iterator find(Checksum checksum, N64FormatSize n64FmtSz) const;
uint8 *_gzdest0 = nullptr;
uint8 *_gzdest1 = nullptr;
@ -524,12 +569,15 @@ private:
std::ofstream _outfile;
int64 _storagePos = 0;
bool _dirty = false;
bool _isOldVersion = false;
static const int _fakeConfig;
static const int64 _initialPos;
static const int64 _initialPosOld;
};
const int TxFileStorage::_fakeConfig = -1;
const int64 TxFileStorage::_initialPos = sizeof(int64) + sizeof(int);
const int64 TxFileStorage::_initialPos = sizeof(int64) + sizeof(int) + sizeof(int); // offset + version + config
const int64 TxFileStorage::_initialPosOld = sizeof(int64) + sizeof(int); // offset + config
TxFileStorage::TxFileStorage(uint32 options,
const wchar_t *cachePath,
@ -594,6 +642,8 @@ bool TxFileStorage::open(bool forRead)
if (!_outfile.good())
return false;
const int version = TXCACHE_FORMAT_VERSION;
FWRITE(version);
FWRITE(_fakeConfig);
_storagePos = _initialPos;
FWRITE(_storagePos);
@ -616,6 +666,8 @@ void TxFileStorage::clear()
_outfile.close();
_outfile.open(_fullPath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
const int version = TXCACHE_FORMAT_VERSION;
FWRITE(version);
FWRITE(_fakeConfig);
_storagePos = _initialPos;
FWRITE(_storagePos);
@ -632,6 +684,7 @@ bool TxFileStorage::writeData(uint32 dataSize, const GHQTexInfo & info)
FWRITE(info.texture_format);
FWRITE(info.pixel_type);
FWRITE(info.is_hires_tex);
FWRITE(info.n64_format_size._formatsize);
FWRITE(dataSize);
_outfile.write((char*)info.data, dataSize);
return _outfile.good();
@ -645,6 +698,8 @@ bool TxFileStorage::readData(GHQTexInfo & info)
FREAD(info.texture_format);
FREAD(info.pixel_type);
FREAD(info.is_hires_tex);
if (!_isOldVersion)
FREAD(info.n64_format_size._formatsize);
uint32 dataSize = 0U;
FREAD(dataSize);
@ -679,7 +734,7 @@ bool TxFileStorage::add(Checksum checksum, GHQTexInfo *info, int dataSize)
{
/* NOTE: dataSize must be provided if info->data is zlib compressed. */
if (!checksum || !info->data || _storage.find(checksum) != _storage.end())
if (!checksum || !info->data || isCached(checksum, info->n64_format_size))
return false;
if (_infile.is_open() || !_outfile.is_open())
@ -724,8 +779,12 @@ bool TxFileStorage::add(Checksum checksum, GHQTexInfo *info, int dataSize)
_outfile.seekp(_storagePos, std::ofstream::beg);
assert(_storagePos == _outfile.tellp());
assert(_storagePos < 0xFFFFFFFFFFFFFF);
_storage.insert(StorageMap::value_type(checksum._checksum, _storagePos));
StorageOffset offset;
offset._formatsize = info->n64_format_size.formatsize();
offset._offset = _storagePos;
_storage.insert(StorageMap::value_type(checksum._checksum, offset));
if (!writeData(dataSize, infoToWrite))
return false;
_storagePos = _outfile.tellp();
@ -733,7 +792,7 @@ bool TxFileStorage::add(Checksum checksum, GHQTexInfo *info, int dataSize)
#ifdef DEBUG
DBG_INFO(80, wst("[%5d] added!! crc:%08X %08X %d x %d gfmt:%x total:%.02fmb\n"),
_storage.size(), checksum._hi, checksum._low,
_storage.size(), checksum._palette, checksum._texture,
info->width, info->height, info->format & 0xffff, (double)(_totalSize / 1024) / 1024.0);
#endif
@ -743,13 +802,26 @@ bool TxFileStorage::add(Checksum checksum, GHQTexInfo *info, int dataSize)
return true;
}
bool TxFileStorage::get(Checksum checksum, GHQTexInfo *info)
TxFileStorage::StorageMap::const_iterator TxFileStorage::find(Checksum checksum, N64FormatSize n64FmtSz) const
{
if (_isOldVersion)
return _storage.find(checksum);
auto range = _storage.equal_range(checksum);
for (auto it = range.first; it != range.second; ++it) {
if (static_cast<uint16>(it->second._formatsize) == n64FmtSz.formatsize())
return it;
}
return _storage.cend();
}
bool TxFileStorage::get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
if (!checksum || _storage.empty())
return false;
/* find a match in storage */
auto itMap = _storage.find(checksum);
auto itMap = find(checksum, n64FmtSz);
if (itMap == _storage.end())
return false;
@ -757,7 +829,7 @@ bool TxFileStorage::get(Checksum checksum, GHQTexInfo *info)
if (!open(true))
return false;
_infile.seekg(itMap->second, std::ifstream::beg);
_infile.seekg(itMap->second._offset, std::ifstream::beg);
return readData(*info);
}
@ -782,6 +854,8 @@ bool TxFileStorage::save(const wchar_t *path, const wchar_t *filename, int confi
_outfile.seekp(0L, std::ofstream::beg);
int version = TXCACHE_FORMAT_VERSION;
FWRITE(version);
FWRITE(config);
FWRITE(_storagePos);
_outfile.seekp(_storagePos, std::ofstream::beg);
@ -791,7 +865,7 @@ bool TxFileStorage::save(const wchar_t *path, const wchar_t *filename, int confi
(*_callback)(wst("Saving texture storage...\n"));
for (auto& item : _storage) {
FWRITE(item.first);
FWRITE(item.second);
FWRITE(item.second._data);
}
_outfile.close();
if (_callback)
@ -813,19 +887,38 @@ bool TxFileStorage::load(const wchar_t *path, const wchar_t *filename, int confi
if (!open(true))
return false;
int version = 0;
int tmpconfig = 0;
/* read header to determine config match */
/* read version */
_infile.seekg(0L, std::ifstream::beg);
FREAD(tmpconfig);
FREAD(_storagePos);
if (tmpconfig == _fakeConfig) {
if (_storagePos != _initialPos)
FREAD(version);
if (version == TXCACHE_FORMAT_VERSION) {
_isOldVersion = false;
/* read header to determine config match */
FREAD(tmpconfig);
FREAD(_storagePos);
if (tmpconfig == _fakeConfig) {
if (_storagePos != _initialPos)
return false;
} else if (tmpconfig != config && !force)
return false;
} else if (tmpconfig != config && !force)
return false;
if (_storagePos <= sizeof(config) + sizeof(_storagePos))
return false;
if (_storagePos <= _initialPos)
return false;
} else {
_isOldVersion = true;
tmpconfig = version;
FREAD(_storagePos);
if (tmpconfig == _fakeConfig) {
if (_storagePos != _initialPosOld)
return false;
} else if (tmpconfig != config && !force)
return false;
if (_storagePos <= _initialPosOld)
return false;
}
_infile.seekg(_storagePos, std::ifstream::beg);
int storageSize = 0;
@ -849,9 +942,9 @@ bool TxFileStorage::load(const wchar_t *path, const wchar_t *filename, int confi
return !_storage.empty();
}
bool TxFileStorage::isCached(Checksum checksum)
bool TxFileStorage::isCached(Checksum checksum, N64FormatSize n64FmtSz) const
{
return _storage.find(checksum) != _storage.end();
return find(checksum, n64FmtSz) != _storage.cend();
}
/************************** TxCache *************************************/
@ -886,9 +979,9 @@ bool TxCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
return _pImpl->add(checksum, info, dataSize);
}
bool TxCache::get(Checksum checksum, GHQTexInfo *info)
bool TxCache::get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
return _pImpl->get(checksum, info);
return _pImpl->get(checksum, n64FmtSz, info);
}
uint64 TxCache::size() const
@ -921,9 +1014,9 @@ bool TxCache::del(Checksum checksum)
return _pImpl->del(checksum);
}
bool TxCache::isCached(Checksum checksum)
bool TxCache::isCached(Checksum checksum, N64FormatSize n64FmtSz) const
{
return _pImpl->isCached(checksum);
return _pImpl->isCached(checksum, n64FmtSz);
}
void TxCache::clear()

View File

@ -31,27 +31,6 @@
#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
@ -66,8 +45,8 @@ protected:
bool save();
bool load(bool force);
bool del(Checksum checksum); /* checksum hi:palette low:texture */
bool isCached(Checksum checksum); /* checksum hi:palette low:texture */
bool del(Checksum checksum);
bool isCached(Checksum checksum, N64FormatSize n64FmtSz) const;
void clear();
uint64 size() const; // number of elements
uint64 totalSize() const; // size of elements in bytes
@ -82,7 +61,7 @@ public:
virtual ~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 get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info);
bool empty() const;
};

View File

@ -164,7 +164,7 @@ TxFilter::TxFilter(int maxwidth,
}
boolean
TxFilter::filter(uint8 *src, int srcwidth, int srcheight, ColorFormat srcformat, uint64 g64crc, GHQTexInfo *info)
TxFilter::filter(uint8 *src, int srcwidth, int srcheight, ColorFormat srcformat, uint64 g64crc, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
uint8 *texture = src;
uint8 *tmptex = _tex1;
@ -186,7 +186,7 @@ TxFilter::filter(uint8 *src, int srcwidth, int srcheight, ColorFormat srcformat,
/* check if we have it in cache */
if ((g64crc & 0xffffffff00000000) == 0 && /* we reach here only when there is no hires texture for this crc */
_txTexCache->get(g64crc, info)) {
_txTexCache->get(g64crc, n64FmtSz, info)) {
DBG_INFO(80, wst("cache hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
return 1; /* yep, we've got it */
}
@ -451,6 +451,7 @@ TxFilter::filter(uint8 *src, int srcwidth, int srcheight, ColorFormat srcformat,
info->width = srcwidth;
info->height = srcheight;
info->is_hires_tex = 0;
info->n64_format_size = n64FmtSz;
setTextureFormat(destformat, info);
/* cache the texture. */
@ -463,7 +464,7 @@ TxFilter::filter(uint8 *src, int srcwidth, int srcheight, ColorFormat srcformat,
}
boolean
TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *info)
TxFilter::hirestex(uint64 g64crc, Checksum r_crc64, uint16 *palette, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
/* NOTE: Rice CRC32 sometimes return the same value for different textures.
* As a workaround, Glide64 CRC32 is used for the key for NON-hires
@ -476,13 +477,13 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
*/
DBG_INFO(80, wst("hirestex: r_crc64:%08X %08X, g64crc:%08X %08X\n"),
(uint32)(r_crc64 >> 32), (uint32)(r_crc64 & 0xffffffff),
r_crc64._palette, r_crc64._texture,
(uint32)(g64crc >> 32), (uint32)(g64crc & 0xffffffff));
#if HIRES_TEXTURE
/* check if we have it in hires memory cache. */
if ((_options & HIRESTEXTURES_MASK) && r_crc64) {
if (_txHiResLoader->get(r_crc64, info)) {
if (_txHiResLoader->get(r_crc64, n64FmtSz, info)) {
DBG_INFO(80, wst("hires hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
/* TODO: Enable emulation for special N64 combiner modes. There are few ways
@ -509,11 +510,11 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
return 1; /* yep, got it */
}
if (_txHiResLoader->get((r_crc64 >> 32), info) ||
_txHiResLoader->get((r_crc64 & 0xffffffff), info)) {
if (_txHiResLoader->get(r_crc64._palette, n64FmtSz, info) ||
_txHiResLoader->get(r_crc64._texture, n64FmtSz, info)) {
DBG_INFO(80, wst("hires hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
/* for true CI textures, we use the passed in palette to convert to
/* for true CI textures, we use the passed in palette to convert to
* ARGB1555 and add it to memory cache.
*
* NOTE: we do this AFTER all other texture cache searches because
@ -543,6 +544,7 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
info->width = width;
info->height = height;
info->is_hires_tex = 1;
info->n64_format_size = n64FmtSz;
setTextureFormat(format, info);
/* XXX: add to hires texture cache!!! */
@ -558,7 +560,7 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
/* check if we have it in memory cache */
if (_cacheSize && g64crc) {
if (_txTexCache->get(g64crc, info)) {
if (_txTexCache->get(g64crc, n64FmtSz, info)) {
DBG_INFO(80, wst("cache hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
return 1; /* yep, we've got it */
}
@ -579,7 +581,7 @@ TxFilter::checksum64(uint8 *src, int width, int height, int size, int rowStride,
}
boolean
TxFilter::dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorFormat gfmt, uint16 n64fmt, uint64 r_crc64)
TxFilter::dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorFormat gfmt, N64FormatSize n64FmtSz, Checksum r_crc64)
{
assert(gfmt != graphics::colorFormat::RGBA);
if (!_initialized)
@ -588,9 +590,9 @@ TxFilter::dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorForm
if (!(_options & DUMP_TEX))
return 0;
DBG_INFO(80, wst("gfmt = %02x n64fmt = %02x\n"), u32(gfmt), n64fmt);
DBG_INFO(80, wst("gfmt = %02x n64fmt = %02x\n"), u32(gfmt), n64FmtSz._format);
DBG_INFO(80, wst("hirestex: r_crc64:%08X %08X\n"),
(uint32)(r_crc64 >> 32), (uint32)(r_crc64 & 0xffffffff));
r_crc64._palette, r_crc64._texture);
if (gfmt != graphics::internalcolorFormat::RGBA8) {
if (!_txQuantize->quantize(src, _tex1, rowStridePixel, height, gfmt, graphics::internalcolorFormat::RGBA8))
@ -611,13 +613,13 @@ TxFilter::dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorForm
if (!osal_path_existsW(tmpbuf.c_str()) && osal_mkdirp(tmpbuf.c_str()) != 0)
return 0;
if ((n64fmt >> 8) == 0x2) {
if (n64FmtSz._format == 0x2) {
wchar_t wbuf[256];
tx_swprintf(wbuf, 256, wst("/%ls#%08X#%01X#%01X#%08X_ciByRGBA.png"), _ident.c_str(), (uint32)(r_crc64 & 0xffffffff), (n64fmt >> 8), (n64fmt & 0xf), (uint32)(r_crc64 >> 32));
tx_swprintf(wbuf, 256, wst("/%ls#%08X#%01X#%01X#%08X_ciByRGBA.png"), _ident.c_str(), r_crc64._texture, n64FmtSz._format, n64FmtSz._size, r_crc64._palette);
tmpbuf.append(wbuf);
} else {
wchar_t wbuf[256];
tx_swprintf(wbuf, 256, wst("/%ls#%08X#%01X#%01X_all.png"), _ident.c_str(), (uint32)(r_crc64 & 0xffffffff), (n64fmt >> 8), (n64fmt & 0xf));
tx_swprintf(wbuf, 256, wst("/%ls#%08X#%01X#%01X_all.png"), _ident.c_str(), r_crc64._texture, n64FmtSz._format, n64FmtSz._size);
tmpbuf.append(wbuf);
}

View File

@ -70,13 +70,15 @@ public:
int srcheight,
ColorFormat srcformat,
uint64 g64crc, /* glide64 crc, 64bit for future use */
N64FormatSize n64FmtSz,
GHQTexInfo *info);
boolean hirestex(uint64 g64crc, /* glide64 crc, 64bit for future use */
uint64 r_crc64, /* checksum hi:palette low:texture */
Checksum r_crc64,
uint16 *palette,
N64FormatSize n64FmtSz,
GHQTexInfo *info);
uint64 checksum64(uint8 *src, int width, int height, int size, int rowStride, uint8 *palette);
boolean dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorFormat gfmt, uint16 n64fmt, uint64 r_crc64);
boolean dmptx(uint8 *src, int width, int height, int rowStridePixel, ColorFormat gfmt, N64FormatSize n64FmtSz, Checksum r_crc64);
boolean reloadhirestex();
void dumpcache();
};

View File

@ -57,20 +57,20 @@ txfilter_shutdown(void)
TAPI boolean TAPIENTRY
txfilter_filter(uint8 *src, int srcwidth, int srcheight, uint16 srcformat,
uint64 g64crc, GHQTexInfo *info)
uint64 g64crc, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
if (txFilter)
return txFilter->filter(src, srcwidth, srcheight, ColorFormat(u32(srcformat)),
g64crc, info);
g64crc, n64FmtSz, info);
return 0;
}
TAPI boolean TAPIENTRY
txfilter_hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *info)
txfilter_hirestex(uint64 g64crc, Checksum r_crc64, uint16 *palette, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
if (txFilter)
return txFilter->hirestex(g64crc, r_crc64, palette, info);
return txFilter->hirestex(g64crc, r_crc64, palette, n64FmtSz, info);
return 0;
}
@ -85,10 +85,10 @@ txfilter_checksum(uint8 *src, int width, int height, int size, int rowStride, ui
}
TAPI boolean TAPIENTRY
txfilter_dmptx(uint8 *src, int width, int height, int rowStridePixel, uint16 gfmt, uint16 n64fmt, uint64 r_crc64)
txfilter_dmptx(uint8 *src, int width, int height, int rowStridePixel, uint16 gfmt, N64FormatSize n64FmtSz, Checksum r_crc64)
{
if (txFilter)
return txFilter->dmptx(src, width, height, rowStridePixel, ColorFormat(u32(gfmt)), n64fmt, r_crc64);
return txFilter->dmptx(src, width, height, rowStridePixel, ColorFormat(u32(gfmt)), n64FmtSz, r_crc64);
return 0;
}

View File

@ -45,6 +45,9 @@
#define CHDIR(a) chdir(a)
#endif
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
#ifdef __MSC__
typedef __int64 int64;
typedef unsigned __int64 uint64;
@ -100,21 +103,77 @@ typedef unsigned char boolean;
#define GZ_HIRESTEXCACHE 0x00800000
#define DUMP_TEXCACHE 0x01000000
#define DUMP_HIRESTEXCACHE 0x02000000
#define TILE_HIRESTEX 0x04000000
#define UNDEFINED_0 0x08000000
#define UNDEFINED_0 0x04000000
#define UNDEFINED_1 0x08000000
#define FORCE16BPP_HIRESTEX 0x10000000
#define FORCE16BPP_TEX 0x20000000
#define LET_TEXARTISTS_FLY 0x40000000 /* a little freedom for texture artists */
#define DUMP_TEX 0x80000000
struct GHQTexInfo {
unsigned char *data = nullptr;
int width = 0;
int height = 0;
unsigned int format = 0;
unsigned short texture_format = 0;
unsigned short pixel_type = 0;
unsigned char is_hires_tex = 0;
struct Checksum
{
union
{
uint64 _checksum; /* checksum hi:palette low:texture */
struct
{
uint32 _texture;
uint32 _palette;
};
};
Checksum(uint64 checksum) : _checksum(checksum) {}
Checksum(uint32 texture, uint32 palette) : _texture(texture), _palette(palette) {}
operator bool() const {
return _checksum != 0;
}
operator uint64() const {
return _checksum;
}
};
struct N64FormatSize
{
union
{
uint16 _formatsize;
struct
{
uint8 _format;
uint8 _size;
};
};
N64FormatSize(uint16 n64format, uint16 n64size) :
_format(static_cast<uint8>(n64format)),
_size(static_cast<uint8>(n64size))
{}
uint16 formatsize() const
{
return _formatsize;
}
bool operator==(const N64FormatSize& _other) const
{
return _other._formatsize == _formatsize;
}
};
struct GHQTexInfo
{
GHQTexInfo() {}
~GHQTexInfo() {}
unsigned char *data{ nullptr };
unsigned int width{ 0u };
unsigned int height{ 0u };
unsigned int format{ 0u };
unsigned short texture_format{ 0u };
unsigned short pixel_type{ 0u };
unsigned char is_hires_tex{ 0u };
N64FormatSize n64_format_size{ 0u, 0u };
};
/* Callback to display hires texture info.
@ -155,10 +214,6 @@ typedef void (*dispInfoFuncExt)(const wchar_t *format, ...);
#endif
#endif // OS_WINDOWS
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
#ifdef __cplusplus
extern "C"{
#endif
@ -173,16 +228,16 @@ txfilter_shutdown(void);
TAPI boolean TAPIENTRY
txfilter_filter(uint8 *src, int srcwidth, int srcheight, uint16 srcformat,
uint64 g64crc, GHQTexInfo *info);
uint64 g64crc, N64FormatSize n64FmtSz, GHQTexInfo *info);
TAPI boolean TAPIENTRY
txfilter_hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *info);
txfilter_hirestex(uint64 g64crc, Checksum r_crc64, uint16 *palette, N64FormatSize n64FmtSz, GHQTexInfo *info);
TAPI uint64 TAPIENTRY
txfilter_checksum(uint8 *src, int width, int height, int size, int rowStride, uint8 *palette);
TAPI boolean TAPIENTRY
txfilter_dmptx(uint8 *src, int width, int height, int rowStridePixel, uint16 gfmt, uint16 n64fmt, uint64 r_crc64);
txfilter_dmptx(uint8 *src, int width, int height, int rowStridePixel, uint16 gfmt, N64FormatSize n64FmtSz, Checksum r_crc64);
TAPI boolean TAPIENTRY
txfilter_reloadhirestex();

View File

@ -97,7 +97,6 @@ int TxHiResCache::_getConfig() const
{
return getOptions() &
(HIRESTEXTURES_MASK |
TILE_HIRESTEX |
FORCE16BPP_HIRESTEX |
GZ_HIRESTEXCACHE |
FILE_HIRESTEXCACHE |
@ -251,7 +250,7 @@ TxHiResCache::LoadResult TxHiResCache::_loadHiResTextures(const wchar_t * dir_pa
chksum64 <<= 32;
chksum64 |= (uint64)chksum;
}
if (isCached(chksum64)) {
if (isCached(chksum64, N64FormatSize(fmt, siz))) {
#if !DEBUG
INFO(80, wst("-----\n"));
INFO(80, wst("file: %s\n"), fname);
@ -281,6 +280,7 @@ TxHiResCache::LoadResult TxHiResCache::_loadHiResTextures(const wchar_t * dir_pa
tmpInfo.width = width;
tmpInfo.height = height;
tmpInfo.is_hires_tex = 1;
tmpInfo.n64_format_size = N64FormatSize(fmt, siz);
setTextureFormat(format, &tmpInfo);
/* remove redundant in cache */
@ -325,7 +325,7 @@ bool TxHiResCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
return TxCache::add(checksum, info, dataSize);
}
bool TxHiResCache::get(Checksum checksum, GHQTexInfo *info)
bool TxHiResCache::get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
return TxCache::get(checksum, info);
return TxCache::get(checksum, n64FmtSz, info);
}

View File

@ -60,7 +60,7 @@ public:
dispInfoFuncExt callback);
bool empty() const override;
bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override;
bool get(Checksum checksum, GHQTexInfo *info) override;
bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) override;
bool reload() override;
void dump() override;
};

View File

@ -571,4 +571,3 @@ uint8_t* TxHiResLoader::loadFileInfoTex(char* fname,
return tex;
}

View File

@ -23,7 +23,7 @@ class TxHiResLoader
protected:
uint32_t checkFileName(char* ident, char* fname, uint32_t* pChksum, uint32_t* pPalchksum, uint32_t* pFmt, uint32_t* pSiz);
uint8_t* loadFileInfoTex(char* fname, int siz, int* pWidth, int* pHeight, uint32_t fmt, ColorFormat* pFormat);
std::unique_ptr<TxImage> _txImage;
std::unique_ptr<TxQuantize> _txQuantize;
std::unique_ptr<TxReSample> _txReSample;
@ -42,7 +42,7 @@ public:
virtual bool empty() const = 0;
virtual bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) = 0;
virtual bool get(Checksum checksum, GHQTexInfo *info) = 0;
virtual bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) = 0;
virtual bool reload() = 0;
virtual void dump() = 0;
};

View File

@ -49,30 +49,44 @@ bool TxHiResNoCache::empty() const
return _filesIndex.empty();
}
bool TxHiResNoCache::get(Checksum checksum, GHQTexInfo *info)
TxHiResNoCache::FileIndexMap::const_iterator TxHiResNoCache::findFile(Checksum checksum, N64FormatSize n64FmtSz) const
{
if (!checksum) {
return false;
auto range = _filesIndex.equal_range(checksum);
for (auto it = range.first; it != range.second; ++it) {
if (N64FormatSize(it->second.fmt, it->second.siz).formatsize() == n64FmtSz.formatsize())
return it;
}
return _filesIndex.end();
}
bool TxHiResNoCache::get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info)
{
if (!checksum)
return false;
#ifdef DEBUG
uint32 chksum = checksum._checksum & 0xffffffff;
uint32 palchksum = checksum._checksum >> 32;
#endif
uint32 chksum = checksum._texture;
uint32 palchksum = checksum._palette;
/* loop over each file from the index and try to match it with checksum */
auto indexEntry = _filesIndex.find(checksum);
if (indexEntry == _filesIndex.end()) {
auto indexEntry = findFile(checksum, n64FmtSz);
if (indexEntry == _filesIndex.cend()) {
DBG_INFO(80, wst("TxNoCache::get: chksum:%08X %08X not found\n"), chksum, palchksum);
return false;
}
fileIndexEntry_t& entry = indexEntry->second;
auto entry = indexEntry->second;
/* make sure to not load the same texture twice */
auto loadedTexMap = _loadedTex.find(checksum);
if (loadedTexMap != _loadedTex.end()) {
auto findTex = [n64FmtSz, this](Checksum checksum)
{
auto range = _loadedTex.equal_range(checksum);
for (auto it = range.first; it != range.second; ++it) {
if (it->second.n64_format_size == n64FmtSz)
return it;
}
return _loadedTex.end();
};
if (auto loadedTexMap = findTex(checksum); loadedTexMap != _loadedTex.end()) {
DBG_INFO(80, wst("TxNoCache::get: cached chksum:%08X %08X found\n"), chksum, palchksum);
*info = loadedTexMap->second;
return true;
@ -113,6 +127,7 @@ bool TxHiResNoCache::get(Checksum checksum, GHQTexInfo *info)
info->width = width;
info->height = height;
info->is_hires_tex = 1;
info->n64_format_size = n64FmtSz;
setTextureFormat(format, info);
/* add to loaded textures */
@ -180,9 +195,8 @@ bool TxHiResNoCache::_createFileIndexInDir(tx_wstring directory, bool update)
uint64 chksum64 = 0;
uint32 chksum = 0, palchksum = 0, length = 0;
fileIndexEntry_t entry;
FileIndexEntry entry;
entry.fmt = entry.siz = 0;
bool ret = false;
wcstombs(entry.fname, foundfilename, MAX_PATH);
@ -205,14 +219,14 @@ bool TxHiResNoCache::_createFileIndexInDir(tx_wstring directory, bool update)
}
/* try to add entry to file index */
ret = _filesIndex.insert(std::map<uint64, fileIndexEntry_t>::value_type(chksum64, entry)).second;
if (!ret) {
if (findFile(chksum64, N64FormatSize(entry.fmt, entry.siz)) != _filesIndex.cend()) {
/* technically we should probably fail here,
* however HTS & HTC both don't fail when there are duplicates,
* so to maintain backwards compatability, we won't either
*/
DBG_INFO(80, wst("TxNoCache::_createFileIndexInDir: failed to add cksum:%08X %08X file:%ls\n"), chksum, palchksum, texturefilename.c_str());
} else {
_filesIndex.insert(std::map<uint64, FileIndexEntry>::value_type(chksum64, entry));
DBG_INFO(80, wst("TxNoCache::_createFileIndexInDir: added cksum:%08X %08X file:%ls\n"), chksum, palchksum, texturefilename.c_str());
}

View File

@ -10,7 +10,7 @@ class TxHiResNoCache : public TxHiResLoader
bool _createFileIndexInDir(tx_wstring directory, bool update);
void _clear();
struct fileIndexEntry_t
struct FileIndexEntry
{
char fname[MAX_PATH];
tx_wstring directory;
@ -21,8 +21,10 @@ class TxHiResNoCache : public TxHiResLoader
tx_wstring _fullTexPath;
tx_wstring _ident;
char _identc[MAX_PATH];
std::map<uint64, fileIndexEntry_t> _filesIndex;
std::map<uint64, GHQTexInfo> _loadedTex;
using FileIndexMap = std::multimap<uint64, FileIndexEntry>;
FileIndexMap _filesIndex;
FileIndexMap::const_iterator findFile(Checksum checksum, N64FormatSize n64FmtSz) const;
std::multimap<uint64, GHQTexInfo> _loadedTex;
dispInfoFuncExt _callback;
public:
~TxHiResNoCache();
@ -37,7 +39,7 @@ class TxHiResNoCache : public TxHiResLoader
dispInfoFuncExt callback);
bool empty() const override;
bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override { return false; }
bool get(Checksum checksum, GHQTexInfo *info) override;
bool get(Checksum checksum, N64FormatSize n64FmtSz, GHQTexInfo *info) override;
bool reload() override;
void dump() override { };
};

View File

@ -53,7 +53,7 @@ TxTexCache::TxTexCache(int options, int cachesize, const wchar_t *cachePath, con
}
}
bool TxTexCache::add(uint64 checksum, GHQTexInfo *info)
bool TxTexCache::add(Checksum checksum, GHQTexInfo *info)
{
const bool res = TxCache::add(checksum, info);
if (res)

View File

@ -37,7 +37,7 @@ private:
public:
~TxTexCache();
TxTexCache(int options, int cachesize, const wchar_t *cachePath, const wchar_t *ident, dispInfoFuncExt callback);
bool add(uint64 checksum /* checksum hi:palette low:texture */, GHQTexInfo *info);
bool add(Checksum checksum, GHQTexInfo *info);
void dump();
};

View File

@ -994,11 +994,10 @@ bool TextureCache::_loadHiresBackground(CachedTexture *_pTexture, u64 & _ricecrc
}
_ricecrc = txfilter_checksum(addr, tile_width,
tile_height, (unsigned short)(gSP.bgImage.format << 8 | gSP.bgImage.size),
bpl, paladdr);
tile_height, gSP.bgImage.size, bpl, paladdr);
GHQTexInfo ghqTexInfo;
// TODO: fix problem with zero texture dimensions on GLideNHQ side.
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, &ghqTexInfo) &&
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, N64FormatSize(_pTexture->format, _pTexture->size), &ghqTexInfo) &&
ghqTexInfo.width != 0 && ghqTexInfo.height != 0) {
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
Context::InitTextureParams params;
@ -1096,7 +1095,7 @@ void TextureCache::_loadBackground(CachedTexture *pTexture)
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
txfilter_dmptx((u8*)pDest, pTexture->width, pTexture->height,
pTexture->width, (u16)u32(glInternalFormat),
(unsigned short)(pTexture->format << 8 | pTexture->size),
N64FormatSize(pTexture->format, pTexture->size),
ricecrc);
}
@ -1106,7 +1105,7 @@ void TextureCache::_loadBackground(CachedTexture *pTexture)
TFH.isInited()) {
GHQTexInfo ghqTexInfo;
if (txfilter_filter((u8*)pDest, pTexture->width, pTexture->height,
(u16)u32(glInternalFormat), (uint64)pTexture->crc, &ghqTexInfo) != 0 &&
(u16)u32(glInternalFormat), pTexture->crc, N64FormatSize(pTexture->format, pTexture->size), &ghqTexInfo) != 0 &&
ghqTexInfo.data != nullptr) {
if (ghqTexInfo.width % 2 != 0 &&
@ -1220,10 +1219,10 @@ bool TextureCache::_loadHiresTexture(u32 _tile, CachedTexture *_pTexture, u64 &
// palette = (rdp.pal_8 + (gSP.textureTile[_t]->palette << 4));
}
_ricecrc = txfilter_checksum(addr, width, height, (unsigned short)(_pTexture->format << 8 | _pTexture->size), bpl, paladdr);
_ricecrc = txfilter_checksum(addr, width, height, _pTexture->size, bpl, paladdr);
GHQTexInfo ghqTexInfo;
// TODO: fix problem with zero texture dimensions on GLideNHQ side.
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, &ghqTexInfo) &&
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, N64FormatSize(_pTexture->format, _pTexture->size), &ghqTexInfo) &&
ghqTexInfo.width != 0 && ghqTexInfo.height != 0) {
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
Context::InitTextureParams params;
@ -1491,7 +1490,7 @@ void TextureCache::_loadFast(u32 _tile, CachedTexture *_pTexture)
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
tmptex.width, (u16)u32(glInternalFormat),
(unsigned short)(_pTexture->format << 8 | _pTexture->size),
N64FormatSize(_pTexture->format, _pTexture->size),
ricecrc);
}
@ -1518,6 +1517,7 @@ void TextureCache::_loadFast(u32 _tile, CachedTexture *_pTexture)
GHQTexInfo ghqTexInfo;
if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
(u16)u32(glInternalFormat), (uint64)_pTexture->crc,
N64FormatSize(_pTexture->format, _pTexture->size),
&ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) {
if (ghqTexInfo.width % 2 != 0 &&
ghqTexInfo.format != u32(internalcolorFormat::RGBA8) &&
@ -1665,7 +1665,7 @@ void TextureCache::_loadAccurate(u32 _tile, CachedTexture *_pTexture)
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
txfilter_dmptx((u8*)(m_tempTextureHolder.data() + texDataOffset), tmptex.width, tmptex.height,
tmptex.width, (u16)u32(glInternalFormat),
(unsigned short)(_pTexture->format << 8 | _pTexture->size),
N64FormatSize(_pTexture->format, _pTexture->size),
ricecrc);
}
@ -1723,7 +1723,7 @@ void TextureCache::_loadAccurate(u32 _tile, CachedTexture *_pTexture)
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
tmptex.width, (u16)u32(glInternalFormat),
(unsigned short)(_pTexture->format << 8 | _pTexture->size),
N64FormatSize(_pTexture->format, _pTexture->size),
ricecrc);
}
@ -1750,6 +1750,7 @@ void TextureCache::_loadAccurate(u32 _tile, CachedTexture *_pTexture)
GHQTexInfo ghqTexInfo;
if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
(u16)u32(glInternalFormat), (uint64)_pTexture->crc,
N64FormatSize(_pTexture->format, _pTexture->size),
&ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) {
if (ghqTexInfo.width % 2 != 0 &&
ghqTexInfo.format != u32(internalcolorFormat::RGBA8) &&