mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 00:59:41 +01:00
Merge pull request #9299 from xebra/fake_mipmap
Fix fake mipmap issue related #5350
This commit is contained in:
commit
bbd74d9efe
13 files changed
+90
-25
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -51,6 +51,7 @@ struct CompatFlags {
|
||||
bool ClearToRAM;
|
||||
bool Force04154000Download;
|
||||
bool DrawSyncEatCycles;
|
||||
bool FakeMipmapChange;
|
||||
};
|
||||
|
||||
class IniFile;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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
@@ -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
|
||||
Reference in new issue
Block a user