Merge branch 'mipmap_fixes'.

This commit is contained in:
NeoBrainX 2013-02-07 20:40:33 +01:00
commit ed0abc9dc5
13 changed files with 41 additions and 55 deletions

View File

@ -218,6 +218,9 @@ void TextureCache::ClearRenderTargets()
bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels) bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels)
{ {
if (levels == 1)
return false;
// Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black // 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 texBasePathTemp[MAX_PATH];
char texPathTemp[MAX_PATH]; char texPathTemp[MAX_PATH];
@ -300,7 +303,7 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int 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 use_mipmaps, unsigned int maxlevel, bool from_tmem)
{ {
if (0 == address) if (0 == address)
return NULL; return NULL;
@ -372,7 +375,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// 2. b) For normal textures, all texture parameters need to match // 2. b) For normal textures, all texture parameters need to match
if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format && if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
entry->num_mipmaps == maxlevel && entry->native_width == nativeW && entry->native_height == nativeH) entry->num_mipmaps > maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
{ {
goto return_entry; goto return_entry;
} }
@ -382,7 +385,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// //
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies? // TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches... // TODO: Actually, it should be enough if the internal texture format matches...
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps == maxlevel) if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps > maxlevel)
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height)) || (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
{ {
// reuse the texture // reuse the texture
@ -428,15 +431,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
} }
} }
// TODO: Cleanup. Plus, we still autogenerate mipmaps in certain cases (we shouldn't do that)
bool isPow2;
unsigned int texLevels; unsigned int texLevels;
isPow2 = !((width & (width - 1)) || (height & (height - 1))); bool use_native_mips;
texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2; texLevels = use_mipmaps ? (maxlevel + 1) : 1;
texLevels = maxlevel ? std::min(texLevels, maxlevel + 1) : texLevels;
using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, 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 use_native_mips = use_mipmaps && !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; texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1;
// create the entry/texture // create the entry/texture
if (NULL == entry) { if (NULL == entry) {
@ -445,9 +445,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// Sometimes, we can get around recreating a texture if only the number of mip levels changes // Sometimes, we can get around recreating a texture if only the number of mip levels changes
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states // e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated // Thus, we don't update this member for every Load, but just whenever the texture gets recreated
// // TODO: D3D9 doesn't support min_lod. We should add a workaround for that here!
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels? entry->num_mipmaps = maxlevel + 1;
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
entry->type = TCET_NORMAL; entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
@ -460,13 +459,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
else entry->type = TCET_NORMAL; else entry->type = TCET_NORMAL;
// load texture // load texture
entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); entry->Load(width, height, expandedWidth, 0);
if (g_ActiveConfig.bDumpTextures && !using_custom_texture) if (g_ActiveConfig.bDumpTextures && !using_custom_texture)
DumpTexture(entry, 0); 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 && UseNativeMips) if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && use_native_mips)
{ {
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat); const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
@ -495,7 +494,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
expandedHeight = (currentHeight + bsh) & (~bsh); expandedHeight = (currentHeight + bsh) & (~bsh);
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);
if (g_ActiveConfig.bDumpTextures) if (g_ActiveConfig.bDumpTextures)
DumpTexture(entry, level); DumpTexture(entry, level);
@ -518,7 +517,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight); LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight);
entry->Load(currentWidth, currentHeight, currentWidth, level, false); entry->Load(currentWidth, currentHeight, currentWidth, level);
mipWidth >>= 1; mipWidth >>= 1;
mipHeight >>= 1; mipHeight >>= 1;

View File

@ -89,7 +89,7 @@ public:
virtual bool Save(const char filename[], unsigned int level) = 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) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid, bool isIntensity, bool scaleByHalf, unsigned int cbufid,
@ -116,7 +116,7 @@ public:
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 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, 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); int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat, static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf); const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);

View File

@ -1420,7 +1420,7 @@ void Renderer::SetSamplerState(int stage, int texindex)
// When mipfilter is set to "none", just disable mipmapping altogether // When mipfilter is set to "none", just disable mipmapping altogether
gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f; gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f;
gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f; gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f;
gx_state.sampdc[stage].MipLODBias = (float)tm0.lod_bias/32.0f; gx_state.sampdc[stage].MipLODBias = (s32)tm0.lod_bias/32.0f;
} }
void Renderer::SetInterlacingMode() void Renderer::SetInterlacingMode()

View File

@ -59,12 +59,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage); D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
if (autogen_mips)
PD3DX11FilterTexture(D3D::context, texture->GetTex(), 0, D3DX11_DEFAULT);
} }
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,

View File

@ -41,7 +41,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false); unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -237,8 +237,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)

View File

@ -1333,9 +1333,10 @@ void Renderer::SetSamplerState(int stage, int texindex)
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]);
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]);
float lodbias = tm0.lod_bias / 32.0f;
float lodbias = (s32)tm0.lod_bias / 32.0f;
D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias); D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias);
D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4); D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.max_lod >> 4);
} }
void Renderer::SetInterlacingMode() void Renderer::SetInterlacingMode()

View File

@ -72,10 +72,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level); D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level);
// D3D9 will automatically generate mip maps if necessary
} }
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,

View File

@ -44,7 +44,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false); unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -333,8 +333,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)

View File

@ -183,7 +183,7 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
//glEnable(GL_TEXTURE_2D); //glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
@ -194,16 +194,7 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
if (expanded_width != width) if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
if (bHaveMipMaps && autogen_mips)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp); glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
}
else
{
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
}
if (expanded_width != width) if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -358,17 +349,16 @@ void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, co
GL_REPEAT, GL_REPEAT,
}; };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
(newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
int filt = newmode.min_filter; int filt = newmode.min_filter;
if (g_ActiveConfig.bForceFiltering && filt < 4) if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4)
filt += 4; // take equivalent forced linear filt += 4; // take equivalent forced linear
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod / 16.f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod / 16.f);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod / 16.f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod / 16.f);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, newmode.lod_bias / 32.0f); glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (s32)newmode.lod_bias / 32.0f);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]);

View File

@ -54,7 +54,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips = false); unsigned int expanded_width, unsigned int level);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -164,8 +164,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)