diff --git a/Source/Core/VideoCommon/Src/HiresTextures.cpp b/Source/Core/VideoCommon/Src/HiresTextures.cpp index 50e8a194af..68b2111d4b 100644 --- a/Source/Core/VideoCommon/Src/HiresTextures.cpp +++ b/Source/Core/VideoCommon/Src/HiresTextures.cpp @@ -90,7 +90,13 @@ void Init(const char *gameCode) } } -PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, int texformat, u8 *data) +bool HiresTexExists(const char* filename) +{ + std::string key(filename); + return textureMap.find(key) != textureMap.end(); +} + +PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, unsigned int *required_size, int texformat, unsigned int data_size, u8 *data) { std::string key(fileName); diff --git a/Source/Core/VideoCommon/Src/HiresTextures.h b/Source/Core/VideoCommon/Src/HiresTextures.h index 409c2cc260..4b0db76fd9 100644 --- a/Source/Core/VideoCommon/Src/HiresTextures.h +++ b/Source/Core/VideoCommon/Src/HiresTextures.h @@ -25,7 +25,8 @@ namespace HiresTextures { void Init(const char *gameCode); -PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, int texformat, u8 *data); +bool HiresTexExists(const char *filename); +PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, unsigned int *required_size, int texformat, unsigned int data_size, u8 *data); }; diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index ce306d55c6..6ebeba2ffb 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -178,13 +178,39 @@ void TextureCache::ClearRenderTargets() iter->second->type = TCET_NORMAL; } -PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsigned int& width, unsigned int& height, u8* dest) +bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels) +{ + // Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black + char texBasePathTemp[MAX_PATH]; + char texPathTemp[MAX_PATH]; + + sprintf(texBasePathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat); + + for (unsigned int level = 1; level < levels; ++level) + { + sprintf(texPathTemp, "%s_mip%i", texBasePathTemp, level); + if (!HiresTextures::HiresTexExists(texPathTemp)) + { + if (level > 1) + WARN_LOG(VIDEO, "Couldn't find custom texture LOD with index %i (filename: %s), disabling custom LODs for this texture", level, texPathTemp); + + return false; + } + } + return true; +} + +PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsigned int level, unsigned int& width, unsigned int& height, u8* dest) { char texPathTemp[MAX_PATH]; unsigned int newWidth = 0; unsigned int newHeight = 0; - sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat); + if (level == 0) + sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat); + else + sprintf(texPathTemp, "%s_%08x_%i_mip%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat, level); + PC_TexFormat ret = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, dest); if (ret != PC_TEX_FMT_NONE) @@ -215,7 +241,7 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level) } else { - sprintf(szTemp, "%s/%s_%08x_%i_mip%d.png", szDir.c_str(), + sprintf(szTemp, "%s/%s_%08x_%i_mip%i.png", szDir.c_str(), SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (entry->hash & 0x00000000FFFFFFFFLL), entry->format & 0xFFFF, level); } @@ -240,6 +266,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, const unsigned int nativeW = width; const unsigned int nativeH = height; + bool using_custom_texture = false; + bool using_custom_lods = false; + u32 texID = address; u64 tex_hash = TEXHASH_INVALID; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup) u64 tlut_hash = TEXHASH_INVALID; @@ -321,11 +350,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, if (g_ActiveConfig.bHiresTextures) { - pcfmt = LoadCustomTexture(tex_hash, texformat, width, height, temp); + pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height, temp); if (pcfmt != PC_TEX_FMT_NONE) { expandedWidth = width; expandedHeight = height; + using_custom_texture = true; } } @@ -336,13 +366,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, bool isPow2; unsigned int texLevels; - UseNativeMips = UseNativeMips && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions isPow2 = !((width & (width - 1)) || (height & (height - 1))); - texLevels = (isPow2 && UseNativeMips && maxlevel) ? - GetPow2(std::max(width, height)) : !isPow2; - - if ((texLevels > (maxlevel + 1)) && maxlevel) - texLevels = maxlevel + 1; + texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2; + texLevels = maxlevel ? std::min(texLevels, maxlevel + 1) : texLevels; + using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels); + UseNativeMips = UseNativeMips && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions + texLevels = (UseNativeMips || using_custom_lods) ? texLevels : !isPow2; // create the entry/texture if (NULL == entry) { @@ -368,12 +397,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, // load texture entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); - // TODO: won't this cause loaded hires textures to be dumped as well? - if (g_ActiveConfig.bDumpTextures) + if (g_ActiveConfig.bDumpTextures && !using_custom_texture) DumpTexture(entry, 0); // 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 && UseNativeMips) { const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat); @@ -404,7 +432,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); entry->Load(currentWidth, currentHeight, expandedWidth, level, false); - // TODO: won't this cause loaded hires textures to be dumped as well? if (g_ActiveConfig.bDumpTextures) DumpTexture(entry, level); @@ -414,6 +441,25 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, ++level; } } + else if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && using_custom_lods) + { + unsigned int level = 1; + unsigned int mipWidth = (width + 1) >> 1; + unsigned int mipHeight = (height + 1) >> 1; + + while ((mipHeight || mipWidth) && (level < texLevels)) + { + unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1; + unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; + + LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight, temp); + entry->Load(currentWidth, currentHeight, currentWidth, level, false); + + mipWidth >>= 1; + mipHeight >>= 1; + ++level; + } + } INCSTAT(stats.numTexturesCreated); SETSTAT(stats.numTexturesAlive, textures.size()); diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index a1d1bfb54c..9d29577c9c 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -126,7 +126,8 @@ protected: static GC_ALIGNED16(u8 *temp); private: - static PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int& width, unsigned int& height, u8* dest); + static bool CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels); + static PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int level, unsigned int& width, unsigned int& height, u8* dest); static void DumpTexture(TCacheEntryBase* entry, unsigned int level);