mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-04 03:46:42 +01:00
Implement texture preloading
This commit is contained in:
parent
dabb35afce
commit
eb01a110c9
@ -173,12 +173,12 @@ void TextureCache::ClearRenderTargets()
|
|||||||
iter = textures.begin(),
|
iter = textures.begin(),
|
||||||
tcend = textures.end();
|
tcend = textures.end();
|
||||||
for (; iter!=tcend; ++iter)
|
for (; iter!=tcend; ++iter)
|
||||||
iter->second->type = TCET_AUTOFETCH;
|
iter->second->type = TCET_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||||
u32 address, unsigned int width, unsigned int height, int texformat,
|
u32 address, unsigned int width, unsigned int height, int texformat,
|
||||||
unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel)
|
unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem)
|
||||||
{
|
{
|
||||||
if (0 == address)
|
if (0 == address)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -203,10 +203,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
if (isPaletteTexture)
|
if (isPaletteTexture)
|
||||||
full_format = texformat | (tlutfmt << 16);
|
full_format = texformat | (tlutfmt << 16);
|
||||||
|
|
||||||
u8* ptr = Memory::GetPointer(address);
|
|
||||||
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
|
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
|
||||||
|
u8* src_data;
|
||||||
|
if (from_tmem) src_data = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE];
|
||||||
|
else src_data = Memory::GetPointer(address);
|
||||||
|
|
||||||
tex_hash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||||
if (isPaletteTexture)
|
if (isPaletteTexture)
|
||||||
{
|
{
|
||||||
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
|
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
|
||||||
@ -225,7 +227,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
tex_hash ^= tlut_hash;
|
tex_hash ^= tlut_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
TCacheEntryBase *entry = textures[texID];
|
TCacheEntryBase *entry = textures[texID]; // TODO: Should use a different texID for preloaded textures!
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
// 1. Calculate reference hash:
|
// 1. Calculate reference hash:
|
||||||
@ -252,7 +254,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
//
|
//
|
||||||
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
|
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
|
||||||
// TODO: Actually, it should be enough if the internal texture format matches...
|
// TODO: Actually, it should be enough if the internal texture format matches...
|
||||||
if ((entry->type == TCET_AUTOFETCH && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|
if ((entry->type == TCET_NORMAL && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|
||||||
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
|
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
|
||||||
{
|
{
|
||||||
// reuse the texture
|
// reuse the texture
|
||||||
@ -283,8 +285,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled
|
||||||
if (pcfmt == PC_TEX_FMT_NONE)
|
if (pcfmt == PC_TEX_FMT_NONE)
|
||||||
pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth,
|
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
|
||||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||||
|
|
||||||
bool isPow2;
|
bool isPow2;
|
||||||
@ -301,13 +304,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
if (NULL == entry) {
|
if (NULL == entry) {
|
||||||
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
|
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
|
||||||
|
|
||||||
// Sometimes, we can get around recreating a texture if only the number of mip levels gets changes
|
// Sometimes, we can get around recreating a texture if only the number of mip levels changes
|
||||||
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
|
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
|
||||||
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
|
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
|
||||||
//
|
//
|
||||||
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
|
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
|
||||||
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
|
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
|
||||||
entry->type = TCET_AUTOFETCH;
|
entry->type = TCET_NORMAL;
|
||||||
|
|
||||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||||
}
|
}
|
||||||
@ -315,13 +318,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
|
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
|
||||||
entry->SetDimensions(nativeW, nativeH, width, height);
|
entry->SetDimensions(nativeW, nativeH, width, height);
|
||||||
entry->hash = tex_hash;
|
entry->hash = tex_hash;
|
||||||
if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_AUTOFETCH;
|
if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_NORMAL;
|
||||||
else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC;
|
else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC;
|
||||||
|
|
||||||
// load texture
|
// load texture
|
||||||
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
|
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
|
||||||
|
|
||||||
// load mips
|
// load mips - TODO: Loading mipmaps from tmem is untested!
|
||||||
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
|
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
|
||||||
{
|
{
|
||||||
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
|
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
|
||||||
@ -329,20 +332,31 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||||||
unsigned int level = 1;
|
unsigned int level = 1;
|
||||||
unsigned int mipWidth = (width + 1) >> 1;
|
unsigned int mipWidth = (width + 1) >> 1;
|
||||||
unsigned int mipHeight = (height + 1) >> 1;
|
unsigned int mipHeight = (height + 1) >> 1;
|
||||||
ptr += texture_size;
|
|
||||||
|
u8* ptr_even = NULL, *ptr_odd = NULL;
|
||||||
|
if (from_tmem)
|
||||||
|
{
|
||||||
|
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
|
||||||
|
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||||
|
}
|
||||||
|
src_data += texture_size;
|
||||||
|
|
||||||
while ((mipHeight || mipWidth) && (level < texLevels))
|
while ((mipHeight || mipWidth) && (level < texLevels))
|
||||||
{
|
{
|
||||||
|
u8** ptr;
|
||||||
|
if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even;
|
||||||
|
else ptr = &src_data;
|
||||||
|
|
||||||
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
||||||
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
||||||
|
|
||||||
expandedWidth = (currentWidth + bsw) & (~bsw);
|
expandedWidth = (currentWidth + bsw) & (~bsw);
|
||||||
expandedHeight = (currentHeight + bsh) & (~bsh);
|
expandedHeight = (currentHeight + bsh) & (~bsh);
|
||||||
|
|
||||||
TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||||
entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
|
entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
|
||||||
|
|
||||||
ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
|
*ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
|
||||||
mipWidth >>= 1;
|
mipWidth >>= 1;
|
||||||
mipHeight >>= 1;
|
mipHeight >>= 1;
|
||||||
++level;
|
++level;
|
||||||
|
@ -32,8 +32,7 @@ class TextureCache
|
|||||||
public:
|
public:
|
||||||
enum TexCacheEntryType
|
enum TexCacheEntryType
|
||||||
{
|
{
|
||||||
TCET_AUTOFETCH, // Most textures, automatically fetched whenever they change
|
TCET_NORMAL,
|
||||||
// TCET_PRELOADED, // Textures which reside in TMEM areas which are manually managed by the game
|
|
||||||
TCET_EC_VRAM, // EFB copy which sits in VRAM and is ready to be used
|
TCET_EC_VRAM, // EFB copy which sits in VRAM and is ready to be used
|
||||||
TCET_EC_DYNAMIC, // EFB copy which sits in RAM and needs to be decoded before being used
|
TCET_EC_DYNAMIC, // EFB copy which sits in RAM and needs to be decoded before being used
|
||||||
};
|
};
|
||||||
@ -115,7 +114,7 @@ public:
|
|||||||
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
|
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
|
||||||
|
|
||||||
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
|
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
|
||||||
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel);
|
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem);
|
||||||
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
||||||
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
|
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
|
||||||
|
|
||||||
|
@ -228,7 +228,8 @@ void VertexManager::vFlush()
|
|||||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||||
tex.texTlut[i&3].tlut_format,
|
tex.texTlut[i&3].tlut_format,
|
||||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||||
(tex.texMode1[i&3].max_lod >> 4));
|
tex.texMode1[i&3].max_lod >> 4,
|
||||||
|
tex.texImage1[i&3].image_type);
|
||||||
|
|
||||||
if (tentry)
|
if (tentry)
|
||||||
{
|
{
|
||||||
|
@ -137,7 +137,8 @@ void VertexManager::vFlush()
|
|||||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||||
tex.texTlut[i&3].tlut_format,
|
tex.texTlut[i&3].tlut_format,
|
||||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||||
(tex.texMode1[i&3].max_lod >> 4));
|
tex.texMode1[i&3].max_lod >> 4,
|
||||||
|
tex.texImage1[i&3].image_type);
|
||||||
|
|
||||||
if (tentry)
|
if (tentry)
|
||||||
{
|
{
|
||||||
|
@ -155,7 +155,8 @@ void VertexManager::vFlush()
|
|||||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||||
tex.texTlut[i&3].tlut_format,
|
tex.texTlut[i&3].tlut_format,
|
||||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||||
(tex.texMode1[i&3].max_lod >> 4));
|
tex.texMode1[i&3].max_lod >> 4,
|
||||||
|
tex.texImage1[i&3].image_type);
|
||||||
|
|
||||||
if (tentry)
|
if (tentry)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user