Merge pull request #9299 from xebra/fake_mipmap

Fix fake mipmap issue related #5350
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2017-02-14 21:34:55 +01:00
commit bbd74d9efe
13 files changed
+90 -25

No files matched your search

+1
View File
@@ -51,6 +51,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "ClearToRAM", &flags_.ClearToRAM);
CheckSetting(iniFile, gameID, "Force04154000Download", &flags_.Force04154000Download);
CheckSetting(iniFile, gameID, "DrawSyncEatCycles", &flags_.DrawSyncEatCycles);
CheckSetting(iniFile, gameID, "FakeMipmapChange", &flags_.FakeMipmapChange);
}
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
+1
View File
@@ -51,6 +51,7 @@ struct CompatFlags {
bool ClearToRAM;
bool Force04154000Download;
bool DrawSyncEatCycles;
bool FakeMipmapChange;
};
class IniFile;
+1 -1
View File
@@ -90,7 +90,7 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl
sClamp = gstate.isTexCoordClampedS();
tClamp = gstate.isTexCoordClampedT();
bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001 || (gstate.texlevel & 0xFFFFFF) == 0x100001 ; // Fix texlevel at 0
bool noMip = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST;
if (maxLevel == 0) {
// Enforce no mip filtering, for safety.
+5
View File
@@ -23,6 +23,7 @@
#include "Common/CommonTypes.h"
#include "Common/MemoryUtil.h"
#include "Core/TextureReplacer.h"
#include "Core/System.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Common/TextureDecoder.h"
@@ -102,6 +103,10 @@ public:
return cache.size();
}
bool IsFakeMipmapChange() {
return PSP_CoreParameter().compat.flags().FakeMipmapChange && gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST;
}
// Wow this is starting to grow big. Soon need to start looking at resizing it.
// Must stay a POD.
struct TexCacheEntry {
+1 -1
View File
@@ -100,7 +100,7 @@ static const CommandTableEntry commandTable[] = {
{ GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
{ GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS }, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
{ GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel },
{ GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET },
{ GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+26 -9
View File
@@ -604,7 +604,10 @@ void TextureCacheDX9::SetTexture(bool force) {
lastBoundTexture = INVALID_TEX;
}
u32 texaddr = gstate.getTextureAddress(0);
u8 level = 0;
if (IsFakeMipmapChange())
level = (gstate.texlevel >> 20) & 0xF;
u32 texaddr = gstate.getTextureAddress(level);
if (!Memory::IsValidAddress(texaddr)) {
// Bind a null texture and return.
pD3Ddevice->SetTexture(0, NULL);
@@ -612,9 +615,9 @@ void TextureCacheDX9::SetTexture(bool force) {
return;
}
const u16 dim = gstate.getTextureDimension(0);
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
const u16 dim = gstate.getTextureDimension(level);
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
GETextureFormat format = gstate.getTextureFormat();
if (format >= 11) {
@@ -1011,7 +1014,11 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry, bool replaceImage
maxLevel = 0;
}
LoadTextureLevel(*entry, replaced, 0, maxLevel, replaceImages, scaleFactor, dstFmt);
if (IsFakeMipmapChange()) {
u8 level = (gstate.texlevel >> 20) & 0xF;
LoadTextureLevel(*entry, replaced, level, maxLevel, replaceImages, scaleFactor, dstFmt);
} else
LoadTextureLevel(*entry, replaced, 0, maxLevel, replaceImages, scaleFactor, dstFmt);
LPDIRECT3DTEXTURE9 &texture = DxTex(entry);
if (!texture) {
return;
@@ -1095,7 +1102,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
int h = gstate.getTextureHeight(level);
LPDIRECT3DTEXTURE9 &texture = DxTex(&entry);
if (level == 0 && (!replaceImages || texture == nullptr)) {
if ((level == 0 || IsFakeMipmapChange()) && (!replaceImages || texture == nullptr)) {
// Create texture
D3DPOOL pool = D3DPOOL_MANAGED;
int usage = 0;
@@ -1115,7 +1122,11 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
tfmt = D3DFMT_A8R8G8B8;
}
}
HRESULT hr = pD3Ddevice->CreateTexture(tw, th, levels, usage, tfmt, pool, &texture, NULL);
HRESULT hr;
if (IsFakeMipmapChange())
hr = pD3Ddevice->CreateTexture(tw, th, 1, usage, tfmt, pool, &texture, NULL);
else
hr = pD3Ddevice->CreateTexture(tw, th, levels, usage, tfmt, pool, &texture, NULL);
if (FAILED(hr)) {
INFO_LOG(G3D, "Failed to create D3D texture");
ReleaseTexture(&entry);
@@ -1124,7 +1135,10 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
}
D3DLOCKED_RECT rect;
texture->LockRect(level, &rect, NULL, 0);
if (IsFakeMipmapChange())
texture->LockRect(0, &rect, NULL, 0);
else
texture->LockRect(level, &rect, NULL, 0);
gpuStats.numTexturesDecoded++;
if (replaced.GetSize(level, w, h)) {
@@ -1191,7 +1205,10 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
}
}
texture->UnlockRect(level);
if (IsFakeMipmapChange())
texture->UnlockRect(0);
else
texture->UnlockRect(level);
}
bool TextureCacheDX9::DecodeTexture(u8 *output, const GPUgstate &state)
+1 -1
View File
@@ -104,7 +104,7 @@ static const CommandTableEntry commandTable[] = {
{GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
{GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
{GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE},
{GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS}, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
{GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel},
{GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE|DIRTY_UVSCALEOFFSET},
{GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
{GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
+16 -6
View File
@@ -686,7 +686,10 @@ void TextureCacheGLES::SetTexture(bool force) {
lastBoundTexture = INVALID_TEX;
}
u32 texaddr = gstate.getTextureAddress(0);
u8 level = 0;
if (IsFakeMipmapChange())
level = (gstate.texlevel >> 20) & 0xF;
u32 texaddr = gstate.getTextureAddress(level);
if (!Memory::IsValidAddress(texaddr)) {
// Bind a null texture and return.
glBindTexture(GL_TEXTURE_2D, 0);
@@ -694,9 +697,9 @@ void TextureCacheGLES::SetTexture(bool force) {
return;
}
const u16 dim = gstate.getTextureDimension(0);
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
const u16 dim = gstate.getTextureDimension(level);
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
GETextureFormat format = gstate.getTextureFormat();
if (format >= 11) {
@@ -1055,7 +1058,11 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag
// be as good quality as the game's own (might even be better in some cases though).
// Always load base level texture here
LoadTextureLevel(*entry, replaced, 0, replaceImages, scaleFactor, dstFmt);
if (IsFakeMipmapChange()) {
u8 level = (gstate.texlevel >> 20) & 0xF;
LoadTextureLevel(*entry, replaced, level, replaceImages, scaleFactor, dstFmt);
} else
LoadTextureLevel(*entry, replaced, 0, replaceImages, scaleFactor, dstFmt);
// Mipmapping only enable when texture scaling disable
if (maxLevel > 0 && scaleFactor == 1) {
@@ -1271,7 +1278,10 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, w, h, components2, dstFmt, pixelData);
} else {
PROFILE_THIS_SCOPE("loadtex");
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components2, dstFmt, pixelData);
if (IsFakeMipmapChange())
glTexImage2D(GL_TEXTURE_2D, 0, components, w, h, 0, components2, dstFmt, pixelData);
else
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components2, dstFmt, pixelData);
if (!lowMemoryMode_) {
GLenum err = glGetError();
if (err == GL_OUT_OF_MEMORY) {
+11
View File
@@ -1106,6 +1106,17 @@ void GPUCommon::Execute_TexOffsetV(u32 op, u32 diff) {
gstate_c.uv.vOff = getFloat24(op);
}
void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
if (diff == 0xFFFFFFFF) return;
gstate.texlevel ^= diff;
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0) {
Flush();
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
gstate.texlevel ^= diff;
}
void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
// This also make skipping drawing very effective.
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
+1
View File
@@ -107,6 +107,7 @@ public:
void Execute_TexScaleV(u32 op, u32 diff);
void Execute_TexOffsetU(u32 op, u32 diff);
void Execute_TexOffsetV(u32 op, u32 diff);
void Execute_TexLevel(u32 op, u32 diff);
void Execute_WorldMtxNum(u32 op, u32 diff);
void Execute_WorldMtxData(u32 op, u32 diff);
+1 -1
View File
@@ -100,7 +100,7 @@ static const CommandTableEntry commandTable[] = {
{ GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
{ GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS }, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
{ GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel },
{ GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET },
{ GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+15 -5
View File
@@ -623,16 +623,19 @@ void TextureCacheVulkan::SetTexture() {
}
#endif
u32 texaddr = gstate.getTextureAddress(0);
u8 level = 0;
if (IsFakeMipmapChange())
level = (gstate.texlevel >> 20) & 0xF;
u32 texaddr = gstate.getTextureAddress(level);
if (!Memory::IsValidAddress(texaddr)) {
// Bind a null texture and return.
lastBoundTexture = nullptr;
return;
}
const u16 dim = gstate.getTextureDimension(0);
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
const u16 dim = gstate.getTextureDimension(level);
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
if (texaddr == 0x04000000 && w == 2 && h == 2) {
// Nonsense bootup texture. Discard.
}
@@ -1082,6 +1085,8 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, VulkanPushBuff
}
if (entry->vkTex) {
u8 level = (gstate.texlevel >> 20) & 0xF;
bool fakeMipmap = IsFakeMipmapChange() && level > 0;
// Upload the texture data.
for (int i = 0; i <= maxLevel; i++) {
int mipWidth = gstate.getTextureWidth(i) * scaleFactor;
@@ -1098,7 +1103,12 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, VulkanPushBuff
if (replaced.Valid()) {
replaced.Load(i, data, stride);
} else {
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
if (fakeMipmap) {
LoadTextureLevel(*entry, (uint8_t *)data, stride, level, scaleFactor, dstFmt);
entry->vkTex->texture_->UploadMip(0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
break;
} else
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
if (replacer.Enabled()) {
replacer.NotifyTextureDecoded(replacedInfo, data, stride, i, mipWidth, mipHeight);
}
+10 -1
View File
@@ -152,4 +152,13 @@ ULJS00145 = true
ULKS46183 = true
ULJS00260 = true
ULJS19041 = true
NPJH50843 = true
NPJH50843 = true
[FakeMipmapChange]
# This hacks separates each mipmap to independent textures to display wrong-size mipmaps.
# For example this requires games like Tactics Ogre(Japanese) to display multi bytes fonts stored in mipmaps.
# See issue #5350.
# Tactics Ogre(Japanese)
ULJM05753 = true
NPJH50348 = true
ULJM06009 = true