2016-08-11 10:21:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include "GSHandler.h"
|
|
|
|
#include "GsCachedArea.h"
|
|
|
|
|
|
|
|
#define TEX0_CLUTINFO_MASK (~0xFFFFFFE000000000ULL)
|
|
|
|
|
|
|
|
template <typename TextureHandleType>
|
|
|
|
class CGsTextureCache
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class CTexture
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void Reset()
|
|
|
|
{
|
|
|
|
m_live = false;
|
|
|
|
m_textureHandle = TextureHandleType();
|
2017-01-28 20:17:05 -05:00
|
|
|
m_cachedArea.ClearDirtyPages();
|
2016-08-11 10:21:55 -04:00
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
uint64 m_tex0 = 0;
|
|
|
|
bool m_live = false;
|
2016-08-11 10:21:55 -04:00
|
|
|
CGsCachedArea m_cachedArea;
|
|
|
|
|
|
|
|
//Platform specific
|
|
|
|
TextureHandleType m_textureHandle;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
MAX_TEXTURE_CACHE = 256,
|
|
|
|
};
|
|
|
|
|
|
|
|
CGsTextureCache()
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0; i < MAX_TEXTURE_CACHE; i++)
|
|
|
|
{
|
|
|
|
m_textureCache.push_back(std::make_shared<CTexture>());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CTexture* Search(const CGSHandler::TEX0& tex0)
|
|
|
|
{
|
|
|
|
uint64 maskedTex0 = static_cast<uint64>(tex0) & TEX0_CLUTINFO_MASK;
|
|
|
|
|
|
|
|
for(auto textureIterator(m_textureCache.begin());
|
2018-04-30 21:01:23 +01:00
|
|
|
textureIterator != m_textureCache.end(); textureIterator++)
|
2016-08-11 10:21:55 -04:00
|
|
|
{
|
|
|
|
auto texture = *textureIterator;
|
|
|
|
if(!texture->m_live) continue;
|
|
|
|
if(maskedTex0 != texture->m_tex0) continue;
|
|
|
|
m_textureCache.erase(textureIterator);
|
|
|
|
m_textureCache.push_front(texture);
|
|
|
|
return texture.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-01-27 18:41:22 -05:00
|
|
|
void Insert(const CGSHandler::TEX0& tex0, TextureHandleType textureHandle)
|
2016-08-11 10:21:55 -04:00
|
|
|
{
|
|
|
|
auto texture = *m_textureCache.rbegin();
|
|
|
|
texture->Reset();
|
|
|
|
|
2020-04-30 18:56:11 -04:00
|
|
|
// DBZ Budokai Tenkaichi 2 and 3 use invalid (empty) buffer sizes.
|
|
|
|
// Account for that, by assuming image width.
|
|
|
|
uint32 bufSize = tex0.GetBufWidth();
|
|
|
|
if(bufSize == 0)
|
|
|
|
{
|
2023-01-18 13:49:48 -05:00
|
|
|
bufSize = std::min<uint32>(tex0.GetWidth(), CGSHandler::TEX0_MAX_TEXTURE_SIZE);
|
2020-04-27 19:25:27 +02:00
|
|
|
}
|
2023-01-18 13:49:48 -05:00
|
|
|
uint32 texHeight = std::min<uint32>(tex0.GetHeight(), CGSHandler::TEX0_MAX_TEXTURE_SIZE);
|
2020-04-27 19:25:27 +02:00
|
|
|
|
2023-01-18 13:49:48 -05:00
|
|
|
texture->m_cachedArea.SetArea(tex0.nPsm, tex0.GetBufPtr(), bufSize, texHeight);
|
2016-08-11 10:21:55 -04:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
texture->m_tex0 = static_cast<uint64>(tex0) & TEX0_CLUTINFO_MASK;
|
2017-01-27 18:41:22 -05:00
|
|
|
texture->m_textureHandle = std::move(textureHandle);
|
2018-04-30 21:01:23 +01:00
|
|
|
texture->m_live = true;
|
2016-08-11 10:21:55 -04:00
|
|
|
|
|
|
|
m_textureCache.pop_back();
|
|
|
|
m_textureCache.push_front(texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvalidateRange(uint32 start, uint32 size)
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
std::for_each(std::begin(m_textureCache), std::end(m_textureCache),
|
|
|
|
[start, size](TexturePtr& texture) { if(texture->m_live) { texture->m_cachedArea.Invalidate(start, size); } });
|
2016-08-11 10:21:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Flush()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
std::for_each(std::begin(m_textureCache), std::end(m_textureCache),
|
|
|
|
[](TexturePtr& texture) { texture->Reset(); });
|
2016-08-11 10:21:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
typedef std::shared_ptr<CTexture> TexturePtr;
|
|
|
|
typedef std::list<TexturePtr> TextureList;
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
TextureList m_textureCache;
|
2016-08-11 10:21:55 -04:00
|
|
|
};
|