diff --git a/Common/GPU/Shader.cpp b/Common/GPU/Shader.cpp index 9eea402f6791..43943449cc91 100644 --- a/Common/GPU/Shader.cpp +++ b/Common/GPU/Shader.cpp @@ -66,7 +66,7 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { bitwiseOps = lang == HLSL_D3D11; framebufferFetchExtension = nullptr; gles = false; - glslES30 = true; + glslES30 = true; // Hm, D3D9 too? glslVersionNumber = 0; lastFragData = nullptr; texture = "texture"; diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 6769df5dbe88..430b83b3e2a1 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -44,7 +44,7 @@ struct ShaderLanguageDesc { const char *framebufferFetchExtension = nullptr; const char *vsOutPrefix = ""; const char *viewportYSign = ""; - bool glslES30 = false; + bool glslES30 = false; // really glslES30Features. TODO: Clean this up. bool bitwiseOps = false; bool forceMatrix4x4 = false; bool coefsFromBuffers = false; diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index a965f1b06264..10b2c42896cc 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -74,6 +74,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "ReportSmallMemstick", &flags_.ReportSmallMemstick); CheckSetting(iniFile, gameID, "MemstickFixedFree", &flags_.MemstickFixedFree); CheckSetting(iniFile, gameID, "DateLimited", &flags_.DateLimited); + CheckSetting(iniFile, gameID, "ReinterpretFramebuffers", &flags_.ReinterpretFramebuffers); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 1d5dfa6372a7..e390e28f424f 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -72,6 +72,7 @@ struct CompatFlags { bool ReportSmallMemstick; bool MemstickFixedFree; bool DateLimited; + bool ReinterpretFramebuffers; }; class IniFile; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 822a9004d264..2a6445e6f1a9 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -503,7 +503,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer if (vfbFormatChanged) { textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_UPDATED); if (vfb->drawnFormat != vfb->format) { - ReformatFramebufferFrom(vfb, vfb->drawnFormat); + ReinterpretFramebufferFrom(vfb, vfb->drawnFormat); } } @@ -517,10 +517,28 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer } } -void FramebufferManagerCommon::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat oldFormat) { +void FramebufferManagerCommon::ReinterpretFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat oldFormat) { if (!useBufferedRendering_ || !vfb->fbo) { return; } + + ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage; + + bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && + (lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx); + if (!doReinterpret) { + // Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil. + if (oldFormat == GE_FORMAT_565) { + // We have to bind here instead of clear, since it can be that no framebuffer is bound. + // The backend can sometimes directly optimize it to a clear. + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret"); + // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. + // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. + gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE); + } + return; + } + GEBufferFormat newFormat = vfb->format; _assert_(newFormat != oldFormat); @@ -595,12 +613,13 @@ void FramebufferManagerCommon::ReformatFramebufferFrom(VirtualFramebuffer *vfb, draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); Draw::Viewport vp = Draw::Viewport{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); + // No vertex buffer - generate vertices in shader. TODO: Switch to a vertex buffer for GLES2/D3D9 compat. draw_->Draw(3, 0); draw_->InvalidateCachedState(); // Unbind. draw_->BindTexture(0, nullptr); - RebindFramebuffer("RebindFramebuffer - After reinterpret"); + RebindFramebuffer("After reinterpret"); shaderManager_->DirtyLastShader(); textureCache_->ForgetLastTexture(); @@ -639,8 +658,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe } } if (vfb->drawnFormat != vfb->format) { - // TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer(). - ReformatFramebufferFrom(vfb, vfb->drawnFormat); + ReinterpretFramebufferFrom(vfb, vfb->drawnFormat); } if (useBufferedRendering_) { diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 9f35afce116f..04422c7970db 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -322,7 +322,7 @@ class FramebufferManagerCommon { const std::vector &Framebuffers() { return vfbs_; } - void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old); + void ReinterpretFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old); protected: virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 31189408ae41..dd67d94ab186 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -957,7 +957,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) // TODO: Kinda ugly, maybe switch direction of the call? GEBufferFormat oldFormat = candidate.fb->format; candidate.fb->format = candidate.match.reinterpretTo; - framebufferManager_->ReformatFramebufferFrom(candidate.fb, oldFormat); + framebufferManager_->ReinterpretFramebufferFrom(candidate.fb, oldFormat); } _dbg_assert_msg_(framebuffer != nullptr, "Framebuffer must not be null."); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index b315d27a8363..044f5113c301 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -421,10 +421,9 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, GetClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); } else { - framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); - gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650); - framebufferManagerD3D11_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer"); // Probably not necessary. + framebufferManagerD3D11_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer"); + framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); } SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); diff --git a/assets/compat.ini b/assets/compat.ini index 1bda7f4fac54..6cd40f5bc3cb 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -794,3 +794,11 @@ ULUS10455 = true # Car Jack Streets - issue #12698 NPUZ00043 = true NPEZ00198 = true + +# This setting will go away in the near future, hopefully we can enable it +# for all games. +[ReinterpretFramebuffers] +# Outrun - issue #11358 +ULES00262 = true +ULUS10064 = true +ULKS46087 = true