Merge branch 'hires-tex-improvements'

This commit is contained in:
NeoBrainX 2012-05-22 08:14:33 +02:00
commit 4131ca8d38
13 changed files with 179 additions and 82 deletions

View File

@ -90,10 +90,15 @@ 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); std::string key(fileName);
if (textureMap.find(key) == textureMap.end()) if (textureMap.find(key) == textureMap.end())
return PC_TEX_FMT_NONE; return PC_TEX_FMT_NONE;
@ -102,23 +107,17 @@ PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned in
int channels; int channels;
u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA); u8 *temp = SOIL_load_image(textureMap[key].c_str(), &width, &height, &channels, SOIL_LOAD_RGBA);
if (temp == NULL) if (temp == NULL)
{ {
ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str()); ERROR_LOG(VIDEO, "Custom texture %s failed to load", textureMap[key].c_str());
SOIL_free_image_data(temp);
return PC_TEX_FMT_NONE; return PC_TEX_FMT_NONE;
} }
if (width > 2048 || height > 2048) *pWidth = width;
{ *pHeight = height;
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;
}
int offset = 0; int offset = 0;
PC_TexFormat returnTex; PC_TexFormat returnTex = PC_TEX_FMT_NONE;
switch (texformat) switch (texformat)
{ {
@ -126,24 +125,32 @@ PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned in
case GX_TF_I8: case GX_TF_I8:
case GX_TF_IA4: case GX_TF_IA4:
case GX_TF_IA8: 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) for (int i = 0; i < width * height * 4; i += 4)
{ {
// Rather than use a luminosity function, just use the most intense color for luminance // 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++] = *std::max_element(temp+i, temp+i+3);
data[offset++] = temp[i+3]; data[offset++] = temp[i+3];
} }
returnTex = PC_TEX_FMT_IA8; returnTex = PC_TEX_FMT_IA8;
break; break;
default: default:
*required_size = width * height * 4;
if (data_size < *required_size)
goto cleanup;
memcpy(data, temp, width * height * 4); memcpy(data, temp, width * height * 4);
returnTex = PC_TEX_FMT_RGBA32; returnTex = PC_TEX_FMT_RGBA32;
break; break;
} }
*pWidth = width;
*pHeight = height;
SOIL_free_image_data(temp);
INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str()); INFO_LOG(VIDEO, "loading custom texture from %s", textureMap[key].c_str());
cleanup:
SOIL_free_image_data(temp);
return returnTex; return returnTex;
} }

View File

@ -25,7 +25,8 @@
namespace HiresTextures namespace HiresTextures
{ {
void Init(const char *gameCode); 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);
}; };

View File

@ -33,13 +33,13 @@ extern int frameCount;
enum enum
{ {
TEMP_SIZE = (2048 * 2048 * 4),
TEXTURE_KILL_THRESHOLD = 200, TEXTURE_KILL_THRESHOLD = 200,
}; };
TextureCache *g_texture_cache; TextureCache *g_texture_cache;
GC_ALIGNED16(u8 *TextureCache::temp) = NULL; GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
unsigned int TextureCache::temp_size;
TextureCache::TexCache TextureCache::textures; TextureCache::TexCache TextureCache::textures;
bool TextureCache::DeferredInvalidate; bool TextureCache::DeferredInvalidate;
@ -50,8 +50,9 @@ TextureCache::TCacheEntryBase::~TCacheEntryBase()
TextureCache::TextureCache() TextureCache::TextureCache()
{ {
temp_size = 2048 * 2048 * 4;
if (!temp) if (!temp)
temp = (u8*)AllocateAlignedMemory(TEMP_SIZE,16); temp = (u8*)AllocateAlignedMemory(temp_size, 16);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures) if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures)
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
@ -178,6 +179,88 @@ void TextureCache::ClearRenderTargets()
iter->second->type = TCET_NORMAL; iter->second->type = TCET_NORMAL;
} }
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)
{
char texPathTemp[MAX_PATH];
unsigned int newWidth = 0;
unsigned int newHeight = 0;
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);
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)
{
width = newWidth;
height = newHeight;
}
return ret;
}
void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level)
{
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());
// 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%i.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, level);
}
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, bool from_tmem) unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem)
@ -194,6 +277,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
const unsigned int nativeW = width; const unsigned int nativeW = width;
const unsigned int nativeH = height; const unsigned int nativeH = height;
bool using_custom_texture = false;
bool using_custom_lods = false;
u32 texID = address; 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 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; u64 tlut_hash = TEXHASH_INVALID;
@ -272,21 +358,15 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
} }
} }
if (g_ActiveConfig.bHiresTextures) if (g_ActiveConfig.bHiresTextures)
{ {
// Load Custom textures pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height);
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);
if (pcfmt != PC_TEX_FMT_NONE) if (pcfmt != PC_TEX_FMT_NONE)
{ {
expandedWidth = width = newWidth; expandedWidth = width;
expandedHeight = height = newHeight; expandedHeight = height;
using_custom_texture = true;
} }
} }
@ -297,13 +377,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
bool isPow2; bool isPow2;
unsigned int texLevels; 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))); isPow2 = !((width & (width - 1)) || (height & (height - 1)));
texLevels = (isPow2 && UseNativeMips && maxlevel) ? texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2;
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);
if ((texLevels > (maxlevel + 1)) && maxlevel) UseNativeMips = UseNativeMips && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
texLevels = maxlevel + 1; texLevels = (UseNativeMips || using_custom_lods) ? texLevels : !isPow2;
// create the entry/texture // create the entry/texture
if (NULL == entry) { if (NULL == entry) {
@ -329,8 +408,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// load texture // load texture
entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
if (g_ActiveConfig.bDumpTextures && !using_custom_texture)
DumpTexture(entry, 0);
// load mips - TODO: Loading mipmaps from tmem is untested! // 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); const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
@ -361,31 +443,33 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
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);
if (g_ActiveConfig.bDumpTextures)
DumpTexture(entry, level);
*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;
} }
} }
else if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && using_custom_lods)
// 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]; unsigned int level = 1;
std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + unsigned int mipWidth = (width + 1) >> 1;
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; unsigned int mipHeight = (height + 1) >> 1;
// make sure that the directory exists while ((mipHeight || mipWidth) && (level < texLevels))
if (false == File::Exists(szDir) || false == File::IsDirectory(szDir)) {
File::CreateDir(szDir.c_str()); unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(), LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight);
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), entry->Load(currentWidth, currentHeight, currentWidth, level, false);
(u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
if (false == File::Exists(szTemp)) mipWidth >>= 1;
entry->Save(szTemp); mipHeight >>= 1;
++level;
}
} }
INCSTAT(stats.numTexturesCreated); INCSTAT(stats.numTexturesCreated);

View File

@ -84,7 +84,7 @@ public:
virtual ~TCacheEntryBase(); virtual ~TCacheEntryBase();
virtual void Bind(unsigned int stage) = 0; 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, virtual void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0; unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
@ -124,8 +124,14 @@ protected:
TextureCache(); TextureCache();
static GC_ALIGNED16(u8 *temp); static GC_ALIGNED16(u8 *temp);
static unsigned int temp_size;
private: 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);
static void DumpTexture(TCacheEntryBase* entry, unsigned int level);
typedef std::map<u32, TCacheEntryBase*> TexCache; typedef std::map<u32, TCacheEntryBase*> TexCache;
static TexCache textures; static TexCache textures;

View File

@ -243,15 +243,6 @@ void VertexManager::Flush()
{ {
// 0s are probably for no manual wrapping needed. // 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->nativeW, tentry->nativeH, 0, 0); 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 else
ERROR_LOG(VIDEO, "error loading texture"); ERROR_LOG(VIDEO, "error loading texture");

View File

@ -34,7 +34,6 @@
// Log in two categories, and save three other options in the same byte // Log in two categories, and save three other options in the same byte
#define CONF_LOG 1 #define CONF_LOG 1
#define CONF_PRIMLOG 2 #define CONF_PRIMLOG 2
#define CONF_SAVETEXTURES 4
#define CONF_SAVETARGETS 8 #define CONF_SAVETARGETS 8
#define CONF_SAVESHADERS 16 #define CONF_SAVESHADERS 16

View File

@ -45,8 +45,16 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
D3D::context->PSSetShaderResources(stage, 1, &texture->GetSRV()); 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)); return SUCCEEDED(PD3DX11SaveTextureToFileA(D3D::context, texture->GetTex(), D3DX11_IFF_PNG, filename));
} }

View File

@ -49,7 +49,7 @@ private:
const float *colmat); const float *colmat);
void Bind(unsigned int stage); 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, TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,

View File

@ -58,9 +58,17 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
D3D::SetTexture(stage, texture); 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, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,

View File

@ -52,7 +52,7 @@ private:
const float *colmat); const float *colmat);
void Bind(unsigned int stage); 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, TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,

View File

@ -76,11 +76,13 @@ static const GLint c_WrapSettings[4] = {
GL_REPEAT, 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<u32> data(width * height); std::vector<u32> data(width * height);
glBindTexture(textarget, tex); 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(); const GLenum err = GL_REPORT_ERROR();
if (GL_NO_ERROR != err) if (GL_NO_ERROR != err)
@ -119,13 +121,13 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
SetTextureParameters(tm0, tm1); 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 // TODO: make ogl dump PNGs
std::string tga_filename(filename); std::string tga_filename(filename);
tga_filename.replace(tga_filename.size() - 3, 3, "tga"); 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, TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
@ -347,7 +349,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
{ {
static int count = 0; static int count = 0;
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), 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);
} }
} }

View File

@ -62,7 +62,7 @@ private:
const float *colmat); const float *colmat);
void Bind(unsigned int stage); void Bind(unsigned int stage);
bool Save(const char filename[]); bool Save(const char filename[], unsigned int level);
private: private:
void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1); 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); 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);
} }

View File

@ -162,15 +162,6 @@ void VertexManager::vFlush()
{ {
// 0s are probably for no manual wrapping needed. // 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0); PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
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);
}
} }
else else
ERROR_LOG(VIDEO, "error loading texture"); ERROR_LOG(VIDEO, "error loading texture");