Remove TextureAddress struct.
This commit is contained in:
parent
c0a4760f0e
commit
ddc815dd7a
|
@ -146,7 +146,7 @@ void TextureCache::Cleanup(int _frameCount)
|
||||||
}
|
}
|
||||||
if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount &&
|
if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount &&
|
||||||
// EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted
|
// EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted
|
||||||
!iter->second->IsUnrecoverable())
|
!iter->second->IsEfbCopy())
|
||||||
{
|
{
|
||||||
FreeTexture(iter->second);
|
FreeTexture(iter->second);
|
||||||
iter = textures.erase(iter);
|
iter = textures.erase(iter);
|
||||||
|
@ -198,14 +198,10 @@ void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
|
||||||
|
|
||||||
bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 range_size) const
|
bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 range_size) const
|
||||||
{
|
{
|
||||||
if (!addr.HasMemAddress())
|
if (addr + size_in_bytes <= range_address)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u32 memaddr = addr.GetMemAddress();
|
if (addr >= range_address + range_size)
|
||||||
if (memaddr + size_in_bytes <= range_address)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (memaddr >= range_address + range_size)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -322,32 +318,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
||||||
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
|
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
|
||||||
tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);
|
tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);
|
||||||
|
|
||||||
// Compute a texture ID; this isn't everything about a texture, rather just
|
|
||||||
// enough to group together textures with related memory addresses.
|
|
||||||
TextureAddress texID;
|
|
||||||
TextureAddress paletteDecodedID;
|
|
||||||
if (from_tmem)
|
|
||||||
{
|
|
||||||
u32 tmem_addr = bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE;
|
|
||||||
if (texformat == GX_TF_RGBA8 && from_tmem)
|
|
||||||
{
|
|
||||||
u32 tmem_odd_addr = bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE;
|
|
||||||
texID = TextureAddress::TMemRGBA8(tmem_addr, tmem_odd_addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texID = TextureAddress::TMem(tmem_addr);
|
|
||||||
if (isPaletteTexture)
|
|
||||||
paletteDecodedID = TextureAddress::TMemPalette(tmem_addr, tlutaddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texID = TextureAddress::Mem(address);
|
|
||||||
if (isPaletteTexture)
|
|
||||||
paletteDecodedID = TextureAddress::MemPalette(address, tlutaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all texture cache entries for the current texture address, and decide whether to use one of
|
// Find all texture cache entries for the current texture address, and decide whether to use one of
|
||||||
// them, or to create a new one
|
// them, or to create a new one
|
||||||
//
|
//
|
||||||
|
@ -372,16 +342,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
||||||
//
|
//
|
||||||
// For efb copies, the entry created in CopyRenderTargetToTexture always has to be used, or else it was
|
// For efb copies, the entry created in CopyRenderTargetToTexture always has to be used, or else it was
|
||||||
// done in vain.
|
// done in vain.
|
||||||
std::pair<TexCache::iterator, TexCache::iterator> iter_range = textures.equal_range(texID);
|
std::pair <TexCache::iterator, TexCache::iterator> iter_range = textures.equal_range(address);
|
||||||
bool palette_decoded_entry = false;
|
|
||||||
if (isPaletteTexture && iter_range.first == iter_range.second)
|
|
||||||
{
|
|
||||||
iter_range = textures.equal_range(paletteDecodedID);
|
|
||||||
palette_decoded_entry = true;
|
|
||||||
}
|
|
||||||
TexCache::iterator iter = iter_range.first;
|
TexCache::iterator iter = iter_range.first;
|
||||||
TexCache::iterator oldest_entry = iter;
|
TexCache::iterator oldest_entry = iter;
|
||||||
int temp_frameCount = 0x7fffffff;
|
int temp_frameCount = 0x7fffffff;
|
||||||
|
TexCache::iterator unconverted_copy = textures.end();
|
||||||
|
|
||||||
while (iter != iter_range.second)
|
while (iter != iter_range.second)
|
||||||
{
|
{
|
||||||
|
@ -398,35 +363,21 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
||||||
// format is complicated because EFB copy formats don't exactly match
|
// format is complicated because EFB copy formats don't exactly match
|
||||||
// texture formats. I'm not sure what effect checking width/height/levels
|
// texture formats. I'm not sure what effect checking width/height/levels
|
||||||
// would have.
|
// would have.
|
||||||
if (!palette_decoded_entry && isPaletteTexture && g_Config.backend_info.bSupportsPaletteConversion)
|
if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion)
|
||||||
{
|
return ReturnEntry(stage, entry);
|
||||||
// Perform palette decoding.
|
|
||||||
// TODO: Skip decoding if we find a match.
|
|
||||||
std::pair<TexCache::iterator, TexCache::iterator> decoded_iter_range = textures.equal_range(paletteDecodedID);
|
|
||||||
while (decoded_iter_range.first != decoded_iter_range.second)
|
|
||||||
{
|
|
||||||
// Pool this texture and make a new one later.
|
|
||||||
FreeTexture(decoded_iter_range.first->second);
|
|
||||||
decoded_iter_range.first = textures.erase(decoded_iter_range.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
TCacheEntryBase *decoded_entry = AllocateTexture(entry->config);
|
// Note that we found an unconverted EFB copy, then continue. We'll
|
||||||
|
// perform the conversion later. Currently, we only convert EFB copies to
|
||||||
decoded_entry->SetGeneralParameters(paletteDecodedID, texture_size, full_format);
|
// palette textures; we could do other conversions if it proved to be
|
||||||
decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1);
|
// beneficial.
|
||||||
decoded_entry->SetHashes(TEXHASH_INVALID);
|
unconverted_copy = iter;
|
||||||
decoded_entry->frameCount = FRAMECOUNT_INVALID;
|
|
||||||
|
|
||||||
g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt);
|
|
||||||
textures.insert(TexCache::value_type(paletteDecodedID, decoded_entry));
|
|
||||||
entry = decoded_entry;
|
|
||||||
}
|
|
||||||
return ReturnEntry(stage, entry);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Keeping an unused entry for an efb copy in the cache is pointless, because a new entry
|
// Aggressively prune EFB copies: if it isn't useful here, it will probably
|
||||||
// will be created in CopyRenderTargetToTexture
|
// never be useful again. It's theoretically possible for a game to do
|
||||||
|
// something weird where the copy could become useful in the future, but in
|
||||||
|
// practice it doesn't happen.
|
||||||
FreeTexture(entry);
|
FreeTexture(entry);
|
||||||
iter = textures.erase(iter);
|
iter = textures.erase(iter);
|
||||||
continue;
|
continue;
|
||||||
|
@ -451,6 +402,23 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unconverted_copy != textures.end())
|
||||||
|
{
|
||||||
|
// Perform palette decoding.
|
||||||
|
TCacheEntryBase *entry = unconverted_copy->second;
|
||||||
|
TCacheEntryBase *decoded_entry = AllocateTexture(entry->config);
|
||||||
|
|
||||||
|
decoded_entry->SetGeneralParameters(address, texture_size, full_format);
|
||||||
|
decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1);
|
||||||
|
decoded_entry->SetHashes(tex_hash ^ tlut_hash);
|
||||||
|
decoded_entry->frameCount = FRAMECOUNT_INVALID;
|
||||||
|
decoded_entry->is_efb_copy = false;
|
||||||
|
|
||||||
|
g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt);
|
||||||
|
textures.insert(TexCache::value_type(address, decoded_entry));
|
||||||
|
return ReturnEntry(stage, decoded_entry);
|
||||||
|
}
|
||||||
|
|
||||||
// If at least one entry was not used for the same frame, overwrite the oldest one
|
// If at least one entry was not used for the same frame, overwrite the oldest one
|
||||||
if (temp_frameCount != 0x7fffffff)
|
if (temp_frameCount != 0x7fffffff)
|
||||||
{
|
{
|
||||||
|
@ -513,11 +481,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
||||||
TCacheEntryBase* entry = AllocateTexture(config);
|
TCacheEntryBase* entry = AllocateTexture(config);
|
||||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||||
|
|
||||||
textures.insert(TexCache::value_type(isPaletteTexture ? paletteDecodedID : texID, entry));
|
textures.insert(TexCache::value_type(address, entry));
|
||||||
|
|
||||||
entry->SetGeneralParameters(isPaletteTexture ? paletteDecodedID : texID, texture_size, full_format);
|
entry->SetGeneralParameters(address, texture_size, full_format);
|
||||||
entry->SetDimensions(nativeW, nativeH, tex_levels);
|
entry->SetDimensions(nativeW, nativeH, tex_levels);
|
||||||
entry->hash = tex_hash ^ tlut_hash;
|
entry->hash = tex_hash ^ tlut_hash;
|
||||||
|
entry->is_efb_copy = false;
|
||||||
|
|
||||||
// load texture
|
// load texture
|
||||||
entry->Load(width, height, expandedWidth, 0);
|
entry->Load(width, height, expandedWidth, 0);
|
||||||
|
@ -873,7 +842,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
||||||
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;
|
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;
|
||||||
|
|
||||||
// remove all texture cache entries at dstAddr
|
// remove all texture cache entries at dstAddr
|
||||||
std::pair <TexCache::iterator, TexCache::iterator> iter_range = textures.equal_range(TextureAddress::Mem(dstAddr));
|
std::pair <TexCache::iterator, TexCache::iterator> iter_range = textures.equal_range(dstAddr);
|
||||||
TexCache::iterator iter = iter_range.first;
|
TexCache::iterator iter = iter_range.first;
|
||||||
while (iter != iter_range.second)
|
while (iter != iter_range.second)
|
||||||
{
|
{
|
||||||
|
@ -891,15 +860,16 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
||||||
TCacheEntryBase* entry = AllocateTexture(config);
|
TCacheEntryBase* entry = AllocateTexture(config);
|
||||||
|
|
||||||
// TODO: Using the wrong dstFormat, dumb...
|
// TODO: Using the wrong dstFormat, dumb...
|
||||||
entry->SetGeneralParameters(TextureAddress::Mem(dstAddr), 0, dstFormat);
|
entry->SetGeneralParameters(dstAddr, 0, dstFormat);
|
||||||
entry->SetDimensions(tex_w, tex_h, 1);
|
entry->SetDimensions(tex_w, tex_h, 1);
|
||||||
entry->SetHashes(TEXHASH_INVALID);
|
entry->SetHashes(TEXHASH_INVALID);
|
||||||
|
|
||||||
entry->frameCount = FRAMECOUNT_INVALID;
|
entry->frameCount = FRAMECOUNT_INVALID;
|
||||||
|
entry->is_efb_copy = true;
|
||||||
|
|
||||||
entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
|
entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
|
||||||
|
|
||||||
textures.insert(TexCache::value_type(TextureAddress::Mem(dstAddr), entry));
|
textures.insert(TexCache::value_type(dstAddr, entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config)
|
TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config)
|
||||||
|
|
|
@ -43,59 +43,16 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
class TextureAddress
|
|
||||||
{
|
|
||||||
u32 address1;
|
|
||||||
u32 address2;
|
|
||||||
enum AddressKind
|
|
||||||
{
|
|
||||||
// A texture in RAM
|
|
||||||
RAM,
|
|
||||||
// A texture loaded into TMEM
|
|
||||||
TMEM,
|
|
||||||
// A texture in RAM, fully decoded using a palette.
|
|
||||||
RAM_PALETTE,
|
|
||||||
// An RGBA8 texture in TMEM.
|
|
||||||
TMEM_RGBA8,
|
|
||||||
// A palette texture in TMEM.
|
|
||||||
TMEM_PALETTE,
|
|
||||||
// Uninitialized address.
|
|
||||||
INVALID
|
|
||||||
};
|
|
||||||
AddressKind kind;
|
|
||||||
TextureAddress(u32 a, u32 b, AddressKind k) : address1(a), address2(b), kind(k) {}
|
|
||||||
public:
|
|
||||||
TextureAddress() : kind(INVALID), address1(0), address2(0) {}
|
|
||||||
static TextureAddress Mem(u32 a) { return TextureAddress(a, 0, RAM); }
|
|
||||||
static TextureAddress MemPalette(u32 a, u32 b) { return TextureAddress(a, b, RAM_PALETTE); }
|
|
||||||
static TextureAddress TMem(u32 a) { return TextureAddress(a, 0, TMEM); }
|
|
||||||
static TextureAddress TMemRGBA8(u32 a, u32 b) { return TextureAddress(a, b, TMEM_RGBA8); }
|
|
||||||
static TextureAddress TMemPalette(u32 a, u32 b) { return TextureAddress(a, b, TMEM_PALETTE); }
|
|
||||||
bool operator == (const TextureAddress& b) const
|
|
||||||
{
|
|
||||||
return kind == b.kind && address1 == b.address1 && address2 == b.address2;
|
|
||||||
}
|
|
||||||
bool operator < (const TextureAddress& b) const
|
|
||||||
{
|
|
||||||
if (kind != b.kind)
|
|
||||||
return kind < b.kind;
|
|
||||||
if (address1 != b.address1)
|
|
||||||
return address1 < b.address1;
|
|
||||||
return address2 < b.address2;
|
|
||||||
}
|
|
||||||
bool IsMemOnlyAddress() const { return kind == RAM; }
|
|
||||||
bool HasMemAddress() const { return kind == RAM || kind == RAM_PALETTE; }
|
|
||||||
u32 GetMemAddress() const { return address1; }
|
|
||||||
};
|
|
||||||
struct TCacheEntryBase
|
struct TCacheEntryBase
|
||||||
{
|
{
|
||||||
const TCacheEntryConfig config;
|
const TCacheEntryConfig config;
|
||||||
|
|
||||||
// common members
|
// common members
|
||||||
TextureAddress addr;
|
u32 addr;
|
||||||
u32 size_in_bytes;
|
u32 size_in_bytes;
|
||||||
u64 hash;
|
u64 hash;
|
||||||
u32 format;
|
u32 format;
|
||||||
|
bool is_efb_copy;
|
||||||
|
|
||||||
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
|
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
|
||||||
unsigned int native_levels;
|
unsigned int native_levels;
|
||||||
|
@ -104,7 +61,7 @@ public:
|
||||||
int frameCount;
|
int frameCount;
|
||||||
|
|
||||||
|
|
||||||
void SetGeneralParameters(TextureAddress _addr, u32 _size, u32 _format)
|
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format)
|
||||||
{
|
{
|
||||||
addr = _addr;
|
addr = _addr;
|
||||||
size_in_bytes = _size;
|
size_in_bytes = _size;
|
||||||
|
@ -138,8 +95,7 @@ public:
|
||||||
|
|
||||||
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
|
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
|
||||||
|
|
||||||
bool IsEfbCopy() { return config.rendertarget; }
|
bool IsEfbCopy() { return is_efb_copy; }
|
||||||
bool IsUnrecoverable() { return IsEfbCopy() && addr.IsMemOnlyAddress(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~TextureCache(); // needs virtual for DX11 dtor
|
virtual ~TextureCache(); // needs virtual for DX11 dtor
|
||||||
|
@ -183,7 +139,7 @@ private:
|
||||||
|
|
||||||
static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry);
|
static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry);
|
||||||
|
|
||||||
typedef std::multimap<TextureAddress, TCacheEntryBase*> TexCache;
|
typedef std::multimap<u32, TCacheEntryBase*> TexCache;
|
||||||
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool;
|
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool;
|
||||||
|
|
||||||
static TexCache textures;
|
static TexCache textures;
|
||||||
|
|
Loading…
Reference in New Issue