From 3ecc5e879c2ca82a021ca7ebbfd4299d192ba178 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 12 May 2012 13:25:13 +0200 Subject: [PATCH 1/6] TextureCacheBase: Move custom texture loading to a helper function --- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 32 ++++++++++++------- .../Core/VideoCommon/Src/TextureCacheBase.h | 4 +++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 00ff9610be..34d4020c86 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -178,6 +178,23 @@ 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) +{ + 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); + PC_TexFormat ret = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, dest); + + if (ret != PC_TEX_FMT_NONE) + { + width = newWidth; + height = newHeight; + } + return ret; +} + TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, u32 address, unsigned int width, unsigned int height, int texformat, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem) @@ -272,21 +289,14 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, } } + if (g_ActiveConfig.bHiresTextures) { - // Load Custom textures - char texPathTemp[MAX_PATH]; - - unsigned int newWidth = width; - unsigned int newHeight = height; - - sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat); - pcfmt = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, temp); - + pcfmt = LoadCustomTexture(tex_hash, texformat, width, height, temp); if (pcfmt != PC_TEX_FMT_NONE) { - expandedWidth = width = newWidth; - expandedHeight = height = newHeight; + expandedWidth = width; + expandedHeight = height; } } diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index 2924c5871f..4252b29d53 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -113,6 +113,7 @@ public: unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 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, 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, @@ -126,6 +127,9 @@ protected: static GC_ALIGNED16(u8 *temp); private: + static PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int& width, unsigned int& height, u8* dest); + + typedef std::map TexCache; static TexCache textures; From a8ad59ee3e4345b9cc2fcf9bfe28e385a7e443c6 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 12 May 2012 13:31:09 +0200 Subject: [PATCH 2/6] TextureCacheBase: Move texture dumping to a helper function. --- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 36 ++++++++++--------- .../Core/VideoCommon/Src/TextureCacheBase.h | 1 + 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 34d4020c86..d01a68954c 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -195,6 +195,24 @@ PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsign return ret; } +void TextureCache::DumpTexture(TCacheEntryBase* entry) +{ + char szTemp[MAX_PATH]; + std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; + + // make sure that the directory exists + if (false == File::Exists(szDir) || false == File::IsDirectory(szDir)) + File::CreateDir(szDir.c_str()); + + sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), + (u32) (entry->hash & 0x00000000FFFFFFFFLL), entry->format & 0xFFFF); // TODO: TLUT format should actually be here as well? :/ + + if (false == File::Exists(szTemp)) + entry->Save(szTemp); +} + TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, u32 address, unsigned int width, unsigned int height, int texformat, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem) @@ -379,24 +397,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, } // TODO: won't this cause loaded hires textures to be dumped as well? - // dump texture to file if (g_ActiveConfig.bDumpTextures) - { - char szTemp[MAX_PATH]; - std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; - - // make sure that the directory exists - if (false == File::Exists(szDir) || false == File::IsDirectory(szDir)) - File::CreateDir(szDir.c_str()); - - sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), - (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat); - - if (false == File::Exists(szTemp)) - entry->Save(szTemp); - } + DumpTexture(entry); 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 4252b29d53..507af0e5ac 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -128,6 +128,7 @@ protected: private: static PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int& width, unsigned int& height, u8* dest); + static void DumpTexture(TCacheEntryBase* entry); typedef std::map TexCache; From a5e68ab10e2655853e7063ce3c7ce1aa31df9db8 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 12 May 2012 13:50:03 +0200 Subject: [PATCH 3/6] TextureCacheBase: Support dumping individual mipmaps. --- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 33 ++++++++++++++----- .../Core/VideoCommon/Src/TextureCacheBase.h | 5 ++- .../Plugin_VideoDX11/Src/TextureCache.cpp | 10 +++++- .../Plugin_VideoDX11/Src/TextureCache.h | 2 +- .../Plugin_VideoDX9/Src/TextureCache.cpp | 12 +++++-- .../Plugin_VideoDX9/Src/TextureCache.h | 2 +- .../Plugin_VideoOGL/Src/TextureCache.cpp | 12 ++++--- .../Plugin_VideoOGL/Src/TextureCache.h | 4 +-- .../Plugin_VideoOGL/Src/VertexManager.cpp | 3 +- 9 files changed, 58 insertions(+), 25 deletions(-) diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index d01a68954c..ce306d55c6 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -195,7 +195,7 @@ PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsign return ret; } -void TextureCache::DumpTexture(TCacheEntryBase* entry) +void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level) { char szTemp[MAX_PATH]; std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + @@ -205,12 +205,23 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry) if (false == File::Exists(szDir) || false == File::IsDirectory(szDir)) File::CreateDir(szDir.c_str()); - sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), - (u32) (entry->hash & 0x00000000FFFFFFFFLL), entry->format & 0xFFFF); // TODO: TLUT format should actually be here as well? :/ + // For compatibility with old texture packs, don't print the LOD index for level 0. + // TODO: TLUT format should actually be stored in filename? :/ + if (level == 0) + { + sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), + (u32) (entry->hash & 0x00000000FFFFFFFFLL), entry->format & 0xFFFF); + } + else + { + sprintf(szTemp, "%s/%s_%08x_%i_mip%d.png", szDir.c_str(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), + (u32) (entry->hash & 0x00000000FFFFFFFFLL), entry->format & 0xFFFF, level); + } if (false == File::Exists(szTemp)) - entry->Save(szTemp); + entry->Save(szTemp, level); } TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, @@ -357,6 +368,10 @@ 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) + DumpTexture(entry, 0); + // load mips - TODO: Loading mipmaps from tmem is untested! if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE) { @@ -389,6 +404,10 @@ 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); + *ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1); mipWidth >>= 1; mipHeight >>= 1; @@ -396,10 +415,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, } } - // TODO: won't this cause loaded hires textures to be dumped as well? - if (g_ActiveConfig.bDumpTextures) - DumpTexture(entry); - 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 507af0e5ac..a1d1bfb54c 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -84,7 +84,7 @@ public: virtual ~TCacheEntryBase(); virtual void Bind(unsigned int stage) = 0; - virtual bool Save(const char filename[]) = 0; + virtual bool Save(const char filename[], unsigned int level) = 0; virtual void Load(unsigned int width, unsigned int height, unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0; @@ -113,7 +113,6 @@ public: unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 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, 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, @@ -128,7 +127,7 @@ protected: private: static PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int& width, unsigned int& height, u8* dest); - static void DumpTexture(TCacheEntryBase* entry); + static void DumpTexture(TCacheEntryBase* entry, unsigned int level); typedef std::map TexCache; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp index e59fbd496e..0e43eb013d 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp @@ -45,8 +45,16 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage) D3D::context->PSSetShaderResources(stage, 1, &texture->GetSRV()); } -bool TextureCache::TCacheEntry::Save(const char filename[]) +bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level) { + // TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) + static bool warn_once = true; + if (level && warn_once) + { + WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!"); + warn_once = false; + return false; + } return SUCCEEDED(PD3DX11SaveTextureToFileA(D3D::context, texture->GetTex(), D3DX11_IFF_PNG, filename)); } diff --git a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.h b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.h index 89c0c66447..59d343017c 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.h @@ -49,7 +49,7 @@ private: const float *colmat); void Bind(unsigned int stage); - bool Save(const char filename[]); + bool Save(const char filename[], unsigned int level); }; TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index 2a3f12ddcf..0d31098c17 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -58,9 +58,17 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage) D3D::SetTexture(stage, texture); } -bool TextureCache::TCacheEntry::Save(const char filename[]) +bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level) { - return SUCCEEDED(PD3DXSaveTextureToFileA(filename, D3DXIFF_PNG, texture, 0)); + IDirect3DSurface9* surface; + HRESULT hr = texture->GetSurfaceLevel(level, &surface); + if (FAILED(hr)) + return false; + + hr = PD3DXSaveSurfaceToFileA(filename, D3DXIFF_PNG, surface, NULL, NULL); + surface->Release(); + + return SUCCEEDED(hr); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h index 6234824c2e..4a7cddd575 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h @@ -52,7 +52,7 @@ private: const float *colmat); void Bind(unsigned int stage); - bool Save(const char filename[]); + bool Save(const char filename[], unsigned int level); }; TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp index f78eb11905..bc1b1f6fc5 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp @@ -76,11 +76,13 @@ static const GLint c_WrapSettings[4] = { GL_REPEAT, }; -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level) { + int width = std::max(virtual_width >> level, 1); + int height = std::max(virtual_height >> level, 1); std::vector data(width * height); glBindTexture(textarget, tex); - glGetTexImage(textarget, 0, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]); + glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]); const GLenum err = GL_REPORT_ERROR(); if (GL_NO_ERROR != err) @@ -119,13 +121,13 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage) SetTextureParameters(tm0, tm1); } -bool TextureCache::TCacheEntry::Save(const char filename[]) +bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level) { // TODO: make ogl dump PNGs std::string tga_filename(filename); tga_filename.replace(tga_filename.size() - 3, 3, "tga"); - return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height); + return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, level); } TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, @@ -347,7 +349,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo { static int count = 0; SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height); + count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0); } } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.h index 866fba33b3..30f44b797d 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.h @@ -62,7 +62,7 @@ private: const float *colmat); void Bind(unsigned int stage); - bool Save(const char filename[]); + bool Save(const char filename[], unsigned int level); private: void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1); @@ -76,7 +76,7 @@ private: TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h); }; -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index dff7f8299e..455952bcb7 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -163,13 +163,14 @@ void VertexManager::vFlush() // 0s are probably for no manual wrapping needed. PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0); + // TODO: Dump this code, it's redundant. if (g_ActiveConfig.iLog & CONF_SAVETEXTURES) { // save the textures char strfile[255]; sprintf(strfile, "%stex%.3d_%d.tga", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_Config.iSaveTargetId, i); - tentry->Save(strfile); + tentry->Save(strfile, 0); } } else From 41d37ab0a0e1236d4e5665c3a7206478ffca2a7f Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 12 May 2012 14:31:38 +0200 Subject: [PATCH 4/6] TextureCacheBase: Support loading custom mipmaps. --- Source/Core/VideoCommon/Src/HiresTextures.cpp | 8 +- Source/Core/VideoCommon/Src/HiresTextures.h | 3 +- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 74 +++++++++++++++---- .../Core/VideoCommon/Src/TextureCacheBase.h | 3 +- 4 files changed, 71 insertions(+), 17 deletions(-) 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); From 72e83140f01b247a4fb0ca7a3eb9afc377d994b4 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 13 May 2012 15:38:56 +0200 Subject: [PATCH 5/6] TextureCacheBase: Remove the texture size limit for custom textures. Only the GPU restrictions for maximum texture size remain. --- Source/Core/VideoCommon/Src/HiresTextures.cpp | 27 ++++++++++--------- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 23 +++++++++++----- .../Core/VideoCommon/Src/TextureCacheBase.h | 3 ++- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Source/Core/VideoCommon/Src/HiresTextures.cpp b/Source/Core/VideoCommon/Src/HiresTextures.cpp index 68b2111d4b..5a3fb051c3 100644 --- a/Source/Core/VideoCommon/Src/HiresTextures.cpp +++ b/Source/Core/VideoCommon/Src/HiresTextures.cpp @@ -99,7 +99,6 @@ 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) { std::string key(fileName); - if (textureMap.find(key) == textureMap.end()) return PC_TEX_FMT_NONE; @@ -108,23 +107,17 @@ PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned in int channels; u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA); - if (temp == NULL) { ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str()); - SOIL_free_image_data(temp); return PC_TEX_FMT_NONE; } - if (width > 2048 || height > 2048) - { - ERROR_LOG(VIDEO, "Custom texture %s is too large (%ix%i); textures can only be 2048 pixels tall and wide", textureMap[key].c_str(), width, height); - SOIL_free_image_data(temp); - return PC_TEX_FMT_NONE; - } + *pWidth = width; + *pHeight = height; int offset = 0; - PC_TexFormat returnTex; + PC_TexFormat returnTex = PC_TEX_FMT_NONE; switch (texformat) { @@ -132,24 +125,32 @@ PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned in case GX_TF_I8: case GX_TF_IA4: case GX_TF_IA8: + *required_size = width * height * 8; + if (data_size < *required_size) + goto cleanup; + for (int i = 0; i < width * height * 4; i += 4) { // Rather than use a luminosity function, just use the most intense color for luminance + // TODO(neobrain): Isn't this kind of.. stupid? data[offset++] = *std::max_element(temp+i, temp+i+3); data[offset++] = temp[i+3]; } returnTex = PC_TEX_FMT_IA8; break; default: + *required_size = width * height * 4; + if (data_size < *required_size) + goto cleanup; + memcpy(data, temp, width * height * 4); returnTex = PC_TEX_FMT_RGBA32; break; } - *pWidth = width; - *pHeight = height; - SOIL_free_image_data(temp); INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str()); +cleanup: + SOIL_free_image_data(temp); return returnTex; } diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 6ebeba2ffb..e2fca05395 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -33,13 +33,13 @@ extern int frameCount; enum { - TEMP_SIZE = (2048 * 2048 * 4), TEXTURE_KILL_THRESHOLD = 200, }; TextureCache *g_texture_cache; GC_ALIGNED16(u8 *TextureCache::temp) = NULL; +unsigned int TextureCache::temp_size; TextureCache::TexCache TextureCache::textures; bool TextureCache::DeferredInvalidate; @@ -50,8 +50,9 @@ TextureCache::TCacheEntryBase::~TCacheEntryBase() TextureCache::TextureCache() { + temp_size = 2048 * 2048 * 4; if (!temp) - temp = (u8*)AllocateAlignedMemory(TEMP_SIZE,16); + temp = (u8*)AllocateAlignedMemory(temp_size, 16); TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures) HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); @@ -200,7 +201,7 @@ bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsign return true; } -PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsigned int level, unsigned int& width, unsigned int& height, u8* dest) +PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsigned int level, unsigned int& width, unsigned int& height) { char texPathTemp[MAX_PATH]; unsigned int newWidth = 0; @@ -211,7 +212,17 @@ PC_TexFormat TextureCache::LoadCustomTexture(u64 tex_hash, int texformat, unsign 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); + unsigned int required_size = 0; + PC_TexFormat ret = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, &required_size, texformat, temp_size, temp); + if (ret == PC_TEX_FMT_NONE && temp_size < required_size) + { + // Allocate more memory and try again + // TODO: Should probably check if newWidth and newHeight are texture dimensions which are actually supported by the current video backend + temp_size = required_size; + FreeAlignedMemory(temp); + temp = (u8*)AllocateAlignedMemory(temp_size, 16); + ret = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, &required_size, texformat, temp_size, temp); + } if (ret != PC_TEX_FMT_NONE) { @@ -350,7 +361,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, if (g_ActiveConfig.bHiresTextures) { - pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height, temp); + pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height); if (pcfmt != PC_TEX_FMT_NONE) { expandedWidth = width; @@ -452,7 +463,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1; unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; - LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight, temp); + LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight); entry->Load(currentWidth, currentHeight, currentWidth, level, false); mipWidth >>= 1; diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index 9d29577c9c..f67ad518c5 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -124,10 +124,11 @@ protected: TextureCache(); static GC_ALIGNED16(u8 *temp); + static unsigned int temp_size; private: 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 PC_TexFormat LoadCustomTexture(u64 tex_hash, int texformat, unsigned int level, unsigned int& width, unsigned int& height); static void DumpTexture(TCacheEntryBase* entry, unsigned int level); From 54aeec7a8ff6b6e5d050637b6cce8df6d9a8b633 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 13 May 2012 17:48:23 +0200 Subject: [PATCH 6/6] Dump the redundant "save textures" function. Use TextureCache's dumping feature instead. --- Source/Core/VideoCommon/Src/VertexManagerBase.cpp | 9 --------- Source/Core/VideoCommon/Src/VideoConfig.h | 1 - Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp | 10 ---------- 3 files changed, 20 deletions(-) diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index 004b0f3cca..d66da30273 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -243,15 +243,6 @@ void VertexManager::Flush() { // 0s are probably for no manual wrapping needed. PixelShaderManager::SetTexDims(i, tentry->nativeW, tentry->nativeH, 0, 0); - - // TODO: - //if (g_ActiveConfig.iLog & CONF_SAVETEXTURES) - //{ - // // save the textures - // char strfile[255]; - // sprintf(strfile, "%stex%.3d_%d.tga", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_Config.iSaveTargetId, i); - // SaveTexture(strfile, GL_TEXTURE_2D, tentry->texture, tentry->w, tentry->h); - //} } else ERROR_LOG(VIDEO, "error loading texture"); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 7c846676bb..e43aa28981 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -34,7 +34,6 @@ // Log in two categories, and save three other options in the same byte #define CONF_LOG 1 #define CONF_PRIMLOG 2 -#define CONF_SAVETEXTURES 4 #define CONF_SAVETARGETS 8 #define CONF_SAVESHADERS 16 diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index 455952bcb7..7be31e7b07 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -162,16 +162,6 @@ void VertexManager::vFlush() { // 0s are probably for no manual wrapping needed. PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0); - - // TODO: Dump this code, it's redundant. - if (g_ActiveConfig.iLog & CONF_SAVETEXTURES) - { - // save the textures - char strfile[255]; - sprintf(strfile, "%stex%.3d_%d.tga", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_Config.iSaveTargetId, i); - tentry->Save(strfile, 0); - } } else ERROR_LOG(VIDEO, "error loading texture");