diff --git a/.gitmodules b/.gitmodules index 57a0d7933e..02c95724d6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "ext/SPIRV-Cross"] path = ext/SPIRV-Cross url = https://github.com/KhronosGroup/SPIRV-Cross.git +[submodule "assets/patches"] + path = assets/patches + url = https://github.com/LunaMoo/PPSSPP_workarounds.git diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 590e0a96fc..f3b34dd7d1 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -52,6 +52,14 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "Force04154000Download", &flags_.Force04154000Download); CheckSetting(iniFile, gameID, "DrawSyncEatCycles", &flags_.DrawSyncEatCycles); CheckSetting(iniFile, gameID, "FakeMipmapChange", &flags_.FakeMipmapChange); + CheckSetting(iniFile, gameID, "HackFixVideo", &flags_.HackFixVideo); + CheckSetting(iniFile, gameID, "HackFixHangs", &flags_.HackFixHangs); + CheckSetting(iniFile, gameID, "HackLatchedFramebuffer", &flags_.HackLatchedFramebuffer); + CheckSetting(iniFile, gameID, "DecreaseVertexDepthAccuracy", &flags_.DecreaseVertexDepthAccuracy); + CheckSetting(iniFile, gameID, "DecreaseFragmentDepthAccuracy", &flags_.DecreaseFragmentDepthAccuracy); + CheckSetting(iniFile, gameID, "ForceRangeDownload", &flags_.ForceRangeDownload); + CheckSetting(iniFile, gameID, "FlushAtStall", &flags_.FlushAtStall); + CheckSetting(iniFile, gameID, "Force04Download", &flags_.Force04Download); CheckSetting(iniFile, gameID, "RequireBufferedRendering", &flags_.RequireBufferedRendering); CheckSetting(iniFile, gameID, "RequireBlockTransfer", &flags_.RequireBlockTransfer); } diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 5354629bcb..754eda949a 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -54,6 +54,14 @@ struct CompatFlags { bool FakeMipmapChange; bool RequireBufferedRendering; bool RequireBlockTransfer; + bool HackFixVideo; + bool HackFixHangs; + bool HackLatchedFramebuffer; + bool DecreaseVertexDepthAccuracy; + bool DecreaseFragmentDepthAccuracy; + bool ForceRangeDownload; + bool FlushAtStall; + bool Force04Download; }; class IniFile; diff --git a/Core/Config.cpp b/Core/Config.cpp index 4f1ffa9850..8b9e929923 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -555,7 +555,6 @@ static ConfigSetting soundSettings[] = { ConfigSetting("AudioBackend", &g_Config.iAudioBackend, 0, true, true), ConfigSetting("AudioLatency", &g_Config.iAudioLatency, 1, true, true), ConfigSetting("ExtraAudioBuffering", &g_Config.bExtraAudioBuffering, false, true, false), - ConfigSetting("SoundSpeedHack", &g_Config.bSoundSpeedHack, false, true, true), ConfigSetting("AudioResampler", &g_Config.bAudioResampler, true, true, true), ConfigSetting("GlobalVolume", &g_Config.iGlobalVolume, VOLUME_MAX, true, true), diff --git a/Core/Config.h b/Core/Config.h index d776b0478e..9e9d54d384 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -227,9 +227,6 @@ public: int iGlobalVolume; bool bExtraAudioBuffering; // For bluetooth - // Audio Hack - bool bSoundSpeedHack; - // UI bool bShowDebuggerOnLoad; int iShowFPSCounter; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index bf22b2d01b..9e7b10a8ea 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -196,6 +196,10 @@ void __AudioShutdown() { } u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { + while (chan.leftVolume > 0x8000) { + chan.leftVolume >>= 1; + chan.rightVolume >>= 1; + } u32 ret = chan.sampleCount; if (chan.sampleAddress == 0) { diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b0a352b6cf..b884f38194 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -866,7 +866,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) } if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { - if ((GEBufferFormat)pixelformat != latchedFramebuf.fmt || linesize != latchedFramebuf.stride) { + if ((GEBufferFormat)pixelformat != latchedFramebuf.fmt || linesize != latchedFramebuf.stride && !PSP_CoreParameter().compat.flags().HackLatchedFramebuffer) { return hleReportError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first"); } } diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index cf82e94e1c..35f814ca84 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -21,6 +21,7 @@ #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" +#include "Core/System.h" #include "GPU/GPUState.h" // Used by TextureDecoder.h when templates get instanced #include "GPU/Common/TextureDecoder.h" #include "GPU/GPUInterface.h" @@ -303,7 +304,7 @@ bool MediaEngine::openContext(bool keepReadPos) { } av_dict_free(&open_opt); - if (!SetupStreams()) { + if (!SetupStreams() || PSP_CoreParameter().compat.flags().HackFixVideo) { // Fallback to old behavior. if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0) { closeContext(); @@ -334,6 +335,10 @@ bool MediaEngine::openContext(bool keepReadPos) { setVideoDim(); m_audioContext = new SimpleAudio(m_audioType, 44100, 2); m_isVideoEnd = false; + if (PSP_CoreParameter().compat.flags().HackFixVideo) { + m_mpegheaderReadPos++; + av_seek_frame(m_pFormatCtx, m_videoStream, 0, 0); + } #endif // USE_FFMPEG return true; } @@ -399,7 +404,12 @@ int MediaEngine::addStreamData(const u8 *buffer, int addSize) { int streamOffset = (int)(*(s32_be *)(m_mpegheader + 8)); if (streamOffset <= m_mpegheaderSize) { m_mpegheaderSize = streamOffset; - m_pdata->pop_front(0, m_mpegheaderSize); + if (PSP_CoreParameter().compat.flags().HackFixVideo) { + int mpegoffset = (int)(*(s32_be*)(m_mpegheader + 8)); + m_pdata->pop_front(0, mpegoffset); + } else { + m_pdata->pop_front(0, m_mpegheaderSize); + } openContext(); } } diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 05d36541f8..7728b36eb8 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -330,15 +330,8 @@ u32 AuCtx::AuDecode(u32 pcmAddr) memset(outbuf, 0, PCMBufSize); // important! empty outbuf to avoid noise u32 outpcmbufsize = 0; - int repeat = 1; - if (g_Config.bSoundSpeedHack){ - repeat = 2; - } - int i = 0; - // decode frames in sourcebuff and output into PCMBuf (each time, we decode one or two frames) - // some games as Miku like one frame each time, some games like DOA like two frames each time - while (sourcebuff.size() > 0 && outpcmbufsize < PCMBufSize && i < repeat){ - i++; + // decode frames in sourcebuff and output into PCMBuf, making sure it's filled + while (sourcebuff.size() > 0 && outpcmbufsize < PCMBufSize) { int pcmframesize; // decode decoder->Decode((void*)sourcebuff.c_str(), (int)sourcebuff.size(), outbuf, &pcmframesize); diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index f1ec9de4a5..27219635b3 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -174,7 +174,10 @@ u32 FramebufferManagerCommon::FramebufferByteSize(const VirtualFramebuffer *vfb) } bool FramebufferManagerCommon::ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const { - return updateVRAM_ || (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x00154000); + return updateVRAM_ || + (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x00154000) || + (PSP_CoreParameter().compat.flags().ForceRangeDownload && vfb->fb_address >= 0x001F3A80 && vfb->fb_address <= 0x001FE7C0) || + (PSP_CoreParameter().compat.flags().Force04Download && vfb->fb_address >= 0x00000000 && vfb->fb_address <= 0x00400000); // Should be vfb->fb_address >= 0x00154000 && vfb->fb_address <= 0x00158000, but nah, let's make it less safe, but more universal } void FramebufferManagerCommon::SetNumExtraFBOs(int num) { diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index c40475f944..abef4473c4 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -127,43 +127,23 @@ int TextureCacheCommon::AttachedDrawingHeight() { return 0; } -// Produces a signed 1.23.8 value. -static int TexLog2(float delta) { - union FloatBits { - float f; - u32 u; - }; - FloatBits f; - f.f = delta; - // Use the exponent as the tex level, and the top mantissa bits for a frac. - // We can't support more than 8 bits of frac, so truncate. - int useful = (f.u >> 15) & 0xFFFF; - // Now offset so the exponent aligns with log2f (exp=127 is 0.) - return useful - 127 * 256; -} - -void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip) { +void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr) { minFilt = gstate.texfilter & 0x7; magFilt = gstate.isMagnifyFilteringEnabled(); sClamp = gstate.isTexCoordClampedS(); tClamp = gstate.isTexCoordClampedT(); - GETexLevelMode mipMode = gstate.getTexLevelMode(); - autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO; - lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f); - if (mipMode == GE_TEXLEVEL_MODE_SLOPE) { - lodBias += 1.0f + TexLog2(gstate.getTextureLodSlope()) * (1.0f / 256.0f); - } - - // If mip level is forced to zero, disable mipmapping. - bool noMip = maxLevel == 0 || (!autoMip && lodBias <= 0.0f); + bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001; // Fix texlevel at 0 if (IsFakeMipmapChange()) - noMip = noMip || !autoMip; + noMip = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST; - if (noMip) { + if (maxLevel == 0) { // Enforce no mip filtering, for safety. minFilt &= 1; // no mipmaps yet lodBias = 0.0f; + } else { + // Texture lod bias should be signed. + lodBias = (float)(int)(s8)((gstate.texlevel >> 16) & 0xFF) / 16.0f; } if (g_Config.iTexFiltering == TEX_FILTER_LINEAR_VIDEO) { @@ -192,6 +172,9 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl magFilt &= ~1; minFilt &= ~1; } + if (noMip) { + minFilt &= 1; + } } void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) { diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 4021121ca1..44be081e50 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -71,9 +71,8 @@ struct SamplerCacheKey { bool tClamp : 1; bool lodAuto : 1; bool : 1; + int8_t lodBias : 8; int8_t maxLevel : 4; - int8_t : 4; - int16_t lodBias : 16; }; }; @@ -248,7 +247,7 @@ protected: } u32 EstimateTexMemoryUsage(const TexCacheEntry *entry); - void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip); + void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr); void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 789f3e4450..00500d8800 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -99,11 +99,11 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device, // Auto selected mip + bias. samp.MaxLOD = key.maxLevel; samp.MinLOD = 0.0f; - samp.MipLODBias = (float)key.lodBias / 256.0f; + samp.MipLODBias = (float)key.lodBias / 16.0f; } else { // Constant mip at bias. - samp.MaxLOD = std::max(0.0f, std::min((float)key.maxLevel, (float)key.lodBias / 256.0f)); - samp.MinLOD = std::max(0.0f, std::min((float)key.maxLevel, (float)key.lodBias / 256.0f)); + samp.MaxLOD = (float)key.lodBias / 16.0f; + samp.MinLOD = (float)key.lodBias / 16.0f; samp.MipLODBias = 0.0f; } #endif @@ -176,19 +176,21 @@ void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheK bool sClamp; bool tClamp; float lodBias; - bool autoMip; u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; key.magFilt = magFilt & 1; key.sClamp = sClamp; key.tClamp = tClamp; - // Don't clamp to maxLevel - this may bias magnify levels. - key.lodBias = (int)(lodBias * 256.0f); + key.lodBias = (s8)((gstate.texlevel >> 16) & 0xFF); + if (key.lodBias > entry.maxLevel * 16) { + key.lodBias = entry.maxLevel * 16; + } key.maxLevel = maxLevel; - key.lodAuto = autoMip; + key.lodAuto = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_AUTO; + // TODO: GE_TEXLEVEL_MODE_SLOPE if (entry.framebuffer) { WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?"); @@ -202,7 +204,7 @@ void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffer bool tClamp; float lodBias; bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); key.minFilt = minFilt & 1; key.mipFilt = 0; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index 5a26ba0755..2e9814a757 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -19,6 +19,7 @@ #include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/ge_constants.h" #include "GPU/Common/GPUStateUtils.h" @@ -507,6 +508,9 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage } else { WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n"); } + if (PSP_CoreParameter().compat.flags().DecreaseFragmentDepthAccuracy) { + WRITE(p, " z /= 2000.0;\n"); // Nasty hack to completely remove flicker in Heroes Phantasia + } WRITE(p, " outfragment.depth = z;\n"); } diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index f7227a8fd0..889322ac04 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -154,19 +154,28 @@ void TextureCacheDX9::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool sClamp; bool tClamp; float lodBias; - bool autoMip; u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr); if (maxLevel != 0) { - if (autoMip) { + GETexLevelMode mode = gstate.getTexLevelMode(); + switch (mode) { + case GE_TEXLEVEL_MODE_AUTO: dxstate.texMaxMipLevel.set(0); dxstate.texMipLodBias.set(lodBias); - } else { + break; + case GE_TEXLEVEL_MODE_CONST: // TODO: This is just an approximation - texMaxMipLevel sets the lowest numbered mip to use. // Unfortunately, this doesn't support a const 1.5 or etc. - dxstate.texMaxMipLevel.set(std::max(0, std::min((int)maxLevel, (int)lodBias))); + dxstate.texMaxMipLevel.set((int)lodBias); dxstate.texMipLodBias.set(-1000.0f); + break; + case GE_TEXLEVEL_MODE_SLOPE: + WARN_LOG_REPORT_ONCE(texSlope, G3D, "Unsupported texture lod slope: %f + %f", gstate.getTextureLodSlope(), lodBias); + // TODO: This behavior isn't correct. + dxstate.texMaxMipLevel.set(0); + dxstate.texMipLodBias.set(lodBias); + break; } entry.lodBias = lodBias; } else { @@ -195,8 +204,7 @@ void TextureCacheDX9::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHe bool sClamp; bool tClamp; float lodBias; - bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); dxstate.texMinFilter.set(MinFilt[minFilt]); dxstate.texMipFilter.set(MipFilt[minFilt]); diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 01fd322a5e..152e2c3fa6 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -26,6 +26,7 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/Directx9/VertexShaderGeneratorDX9.h" #include "GPU/Common/VertexDecoderCommon.h" @@ -258,6 +259,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, " z = (z * u_depthRange.x + u_depthRange.y);\n"); WRITE(p, " z = floor(z);\n"); WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n"); + if (PSP_CoreParameter().compat.flags().DecreaseVertexDepthAccuracy) { + WRITE(p, " z /= 1.000031;\n"); // Hokuto no Ken: Raoh Gaiden - Ten no Haoh + } WRITE(p, " return float4(v.x, v.y, z * v.w, v.w);\n"); WRITE(p, "}\n\n"); } diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 7093f87d3e..75d072104e 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -23,6 +23,7 @@ #include "gfx_es2/gpu_features.h" #include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/ShaderId.h" #include "GPU/GLES/FragmentShaderGeneratorGLES.h" @@ -689,6 +690,9 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer) { } else { WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n"); } + if (PSP_CoreParameter().compat.flags().DecreaseFragmentDepthAccuracy) { + WRITE(p, " z /= 2000.0;\n"); // Nasty hack to completely remove flicker in Heroes Phantasia + } WRITE(p, " gl_FragDepth = z;\n"); } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 044425da19..48b115c517 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -128,31 +128,42 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool sClamp; bool tClamp; float lodBias; - bool autoMip; u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr); - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - if (maxLevel != 0) { - // TODO: What about a swap of autoMip mode? - if (force || entry.lodBias != lodBias) { - if (autoMip) { + if (entry.maxLevel != 0) { + if (force || entry.lodBias != lodBias) { + if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + GETexLevelMode mode = gstate.getTexLevelMode(); + switch (mode) { + case GE_TEXLEVEL_MODE_AUTO: #ifndef USING_GLES2 // Sigh, LOD_BIAS is not even in ES 3.0.. but we could do it in the shader via texture()... glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, lodBias); #endif glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias))); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias))); + break; + case GE_TEXLEVEL_MODE_CONST: + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, lodBias); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, lodBias); + break; + case GE_TEXLEVEL_MODE_SLOPE: + WARN_LOG_REPORT_ONCE(texSlope, G3D, "Unsupported texture lod slope: %f + %f", gstate.getTextureLodSlope(), lodBias); + // TODO: This behavior isn't correct. +#ifndef USING_GLES2 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, lodBias); +#endif + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)entry.maxLevel); + break; } - entry.lodBias = lodBias; } - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0.0f); + entry.lodBias = lodBias; } + } else if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0.0f); } if (force || entry.minFilt != minFilt) { @@ -185,8 +196,7 @@ void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferH bool sClamp; bool tClamp; float lodBias; - bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); minFilt &= 1; // framebuffers can't mipmap. diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index d4812caf5e..719b5cd159 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -29,6 +29,7 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/GLES/VertexShaderGeneratorGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/Common/ShaderId.h" @@ -338,6 +339,9 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) { WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n"); WRITE(p, " z = floor(z);\n"); WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n"); + if (PSP_CoreParameter().compat.flags().DecreaseVertexDepthAccuracy) { + WRITE(p, " z /= 1.000031;\n"); // Hokuto no Ken: Raoh Gaiden - Ten no Haoh + } WRITE(p, " return vec4(v.x, v.y, z * v.w, v.w);\n"); WRITE(p, "}\n\n"); } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c7add7fc2b..a873beced6 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -130,7 +130,6 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, { GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE }, { GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel }, - { GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, { 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 }, @@ -270,6 +269,7 @@ const CommonCommandTableEntry commonCommandTable[] = { // Ignored commands { GE_CMD_TEXFLUSH, 0 }, + { GE_CMD_TEXLODSLOPE, 0 }, { GE_CMD_TEXSYNC, 0 }, // These are just nop or part of other later commands. @@ -744,6 +744,9 @@ u32 GPUCommon::UpdateStall(int listid, u32 newstall) { return SCE_KERNEL_ERROR_ALREADY; dl.stall = newstall & 0x0FFFFFFF; + + if (dl.signal == PSP_GE_SIGNAL_HANDLER_PAUSE && PSP_CoreParameter().compat.flags().HackFixHangs) + dl.signal = PSP_GE_SIGNAL_HANDLER_SUSPEND; guard.unlock(); ProcessDLQueue(); @@ -918,6 +921,9 @@ bool GPUCommon::InterpretList(DisplayList &list) { easy_guard innerGuard(listLock); if (list.pc == list.stall) { gpuState = GPUSTATE_STALL; + if (PSP_CoreParameter().compat.flags().FlushAtStall) { + Flush(); + } downcount = 0; } } @@ -1435,7 +1441,7 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { if (diff == 0xFFFFFFFF) return; gstate.texlevel ^= diff; - if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & gstate.texlevel) != 0) { + if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0) { Flush(); } gstate.texlevel ^= diff; diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 0e691e755c..fe9fe43266 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1058,7 +1058,7 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const break; case GE_TEXLEVEL_MODE_CONST: default: - // Unused value 3 operates the same as CONST. + // Unused value 3 operates the same as CONST. // No it doesn't. detail = 0; break; } diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index f434d16b34..13b074f79a 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -23,6 +23,7 @@ #include "gfx_es2/gpu_features.h" #include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Common/ShaderId.h" #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" @@ -458,6 +459,9 @@ bool GenerateVulkanGLSLFragmentShader(const ShaderID &id, char *buffer) { if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, " highp float z = gl_FragCoord.z;\n"); WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n"); + if (PSP_CoreParameter().compat.flags().DecreaseFragmentDepthAccuracy) { + WRITE(p, " z /= 2000.0;\n"); // Nasty hack to completely remove flicker in Heroes Phantasia + } WRITE(p, " gl_FragDepth = z;\n"); } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index e23324966e..7b0955d987 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -207,9 +207,8 @@ void TextureCacheVulkan::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache bool sClamp; bool tClamp; float lodBias; - bool autoMip; u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; @@ -221,10 +220,17 @@ void TextureCacheVulkan::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache if (entry.maxLevel != 0) { if (force || entry.lodBias != lodBias) { if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - if (autoMip) { + GETexLevelMode mode = gstate.getTexLevelMode(); + switch (mode) { + case GE_TEXLEVEL_MODE_AUTO: // TODO - } else { + break; + case GE_TEXLEVEL_MODE_CONST: + // Sigh, LOD_BIAS is not even in ES 3.0.. + break; + case GE_TEXLEVEL_MODE_SLOPE: // TODO + break; } } entry.lodBias = lodBias; @@ -243,8 +249,7 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe bool sClamp; bool tClamp; float lodBias; - bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); key.minFilt = minFilt & 1; key.mipFilt = 0; diff --git a/README.md b/README.md index f1ce17e963..7d58d2d59e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -PPSSPP - a fast and portable PSP emulator +The aim of this hackish branch is to: + - hackfix stuff that might never get fixed because it's a regression to an unpopular game caused by a fix to popular one etc, + - add my workaround cheat.db as a submodule to distinguish cheats and patches on importing, + - more compat.ini hacks to easier test rare games against known problems and regressions. + + + +PPSSPP - a fast and portable PSP emulator ========================================= Created by Henrik Rydgård diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index a86c45d38e..af45417675 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -178,18 +178,8 @@ UI::EventReturn CwCheatScreen::OnEditCheatFile(UI::EventParams ¶ms) { return UI::EVENT_DONE; } -UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { - if (gameTitle.length() != 9) { - WARN_LOG(COMMON, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameTitle.c_str()); - return UI::EVENT_DONE; - } - std::string line; - std::vector title; +void CwCheatScreen::ParseCheatDB(std::string line, std::vector title, std::vector newList, std::string cheatFile) { bool finished = false, skip = false; - std::vector newList; - - std::string cheatFile = GetSysDirectory(DIRECTORY_CHEATS) + "cheat.db"; - std::fstream fs; File::OpenCPPFile(fs, cheatFile, std::ios::in); @@ -204,7 +194,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { getline(fs, line); title.push_back(line); do { - if (finished == false){ + if (finished == false) { getline(fs, line); } if (line.substr(0, 2) == "_C") { @@ -223,7 +213,8 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { getline(fs, line); } while (line.substr(0, 2) == "_L"); finished = true; - } else { + } + else { continue; } loop:; @@ -234,6 +225,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { break; } fs.close(); + std::string title2; File::OpenCPPFile(fs, activeCheatFile, std::ios::in); getline(fs, title2); @@ -257,6 +249,23 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { } } fs.close(); +} + +UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { + if (gameTitle.length() != 9) { + WARN_LOG(COMMON, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameTitle.c_str()); + return UI::EVENT_DONE; + } + std::string line; + std::vector title; + std::vector newList; + + std::string cheatFile = GetSysDirectory(DIRECTORY_CHEATS) + "cheat.db"; + ParseCheatDB(line, title, newList, cheatFile); + const std::string path = File::GetExeDirectory(); + std::string patchesFile = path + "assets/patches/cheat.db"; + ParseCheatDB(line, title, newList, patchesFile); + g_Config.bReloadCheats = true; //Need a better way to refresh the screen, rather than exiting and having to re-enter. TriggerFinish(DR_OK); diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index e78f8dbdba..feec883dac 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -32,6 +32,7 @@ public: void CreateCodeList(); void processFileOn(std::string activatedCheat); void processFileOff(std::string deactivatedCheat); + void ParseCheatDB(std::string line, std::vector title, std::vector newList, std::string cheatFile); const char * name; std::string activatedCheat, deactivatedCheat; UI::EventReturn OnAddCheat(UI::EventParams ¶ms); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c8754c61a5..045737f875 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -490,9 +490,6 @@ void GameSettingsScreen::CreateViews() { resampling->SetEnabledPtr(&g_Config.bEnableSound); } - audioSettings->Add(new ItemHeader(a->T("Audio hacks"))); - audioSettings->Add(new CheckBox(&g_Config.bSoundSpeedHack, a->T("Sound speed hack (DOA etc.)"))); - // Control ViewGroup *controlsSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); controlsSettingsScroll->SetTag("GameSettingsControls"); diff --git a/assets/compat.ini b/assets/compat.ini index bb0d8869dc..9523aa7763 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -61,7 +61,8 @@ ULAS42282 = true ULJS00378 = true NPJH50579 = true ULJS19069 = true -NPJH50579 = true +# Hokuto no Ken see #7932 ~ missing 2D graphics +ULJM05404 = true [PixelDepthRounding] # Heroes Phantasia requires pixel depth rounding. #6485 (flickering overlaid sprites) @@ -88,6 +89,8 @@ NPJH90002 = true # Phantasy Star Portable 2 JP Demo ULJM91018 = true NPJH90062 = true +# Nayuta no Kiseki see #8744 - flickering textures at some locations +NPJH50625 = true [DepthRangeHack] # Phantasy Star Portable 2 and Infinity both use viewport depth outside [0, 1]. @@ -161,6 +164,17 @@ UCKS45033 = true UCJS18014 = true UCUS98700 = true NPJG00032 = true +# Fixes Patapon 2 title screen double framerate +UCJS10089 = true +NPJG00010 = true +PSPJ30000 = true +UCAS40232 = true +UCAS40239 = true +UCES01177 = true +UCUS98732 = true +UCJS18036 = true +UCAS40292 = true +UCJS18053 = true [FakeMipmapChange] # This hacks separates each mipmap to independent textures to display wrong-size mipmaps. @@ -171,6 +185,73 @@ ULJM05753 = true NPJH50348 = true ULJM06009 = true +[HackFixVideo] +# Revert correct code which broke a game that might be never fixed +# The Warriors +ULUS10213 = true +ULES00483 = true + +[HackFixHangs] +# Revert correct change which again broke some games +# Armored Core 3 Portable +ULJM05492 = true +UCAS40268 = true +NPUH10023 = true +NPEH00045 = true +# Armored Core: Last Raven Portable +ULJM05611 = true +UCAS40302 = true +NPUH10024 = true +NPEH00046 = true +# Armored Core: Silent Line Portable +ULJM05552 = true +UCAS40289 = true +NPUH10025 = true +NPEH00047 = true +# Bleach: Soul Carnival +UCKS45102 = true +ULJS10085 = true +UCAS40227 = true +UCAS40234 = true +UCAS40296 = true +UCJS18038 = true +NPJG00008 = true +# Bleach: Soul Carnival 2 +UCJS10106 = true +NPJG00070 = true +UCAS40291 = true +UCAS40297 = true + +[HackLatchedFramebuffer] +# Auditorium +NPUH10069 = true + +[DecreaseVertexDepthAccuracy] +# Hokuto no Ken: Raoh Gaiden - Ten no Haoh requires vertex depth rounding. +ULJM05404 = true + +[DecreaseFragmentDepthAccuracy] +# Heroes Phantasia requires pixel depth rounding. +NPJH50558 = true +ULJS00456 = true +ULJS00454 = true +# Heroes Phantasia Limited Edition Disc requires pixel depth rounding. +ULJS00455 = true + +[ForceRangeDownload] +# Evangelion Jo #3908 +ULJS00201 = true + +[FlushAtStall] +# Evangelion Jo #3908 +ULJS00201 = true + +[Force04Download] +# Like Force RangeDownload, should have smaller range, but made it bigger for testing other games, +# BTP is fine with it anyway. +# Bijin Tokei Portable not even a game, but needs it to load 2 miniatures, they will be low res, but better than black +NPJH00055 = true + [RequireBufferedRendering] # Warn the user that the game will not work and have issue, if buffered rendering is not enabled. # Midnight Club: LA Remix diff --git a/assets/patches b/assets/patches new file mode 160000 index 0000000000..585e9499bf --- /dev/null +++ b/assets/patches @@ -0,0 +1 @@ +Subproject commit 585e9499bf6ff1dcff4c369779c2841de0a2a553