Merge branch 'hires-tex-improvements'
This commit is contained in:
commit
4131ca8d38
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in New Issue