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