From f9dcac8cd05d8f8a807c422fb33f4233d0cc2108 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 23 Feb 2023 21:00:48 +1000 Subject: [PATCH] GS/HW: Make readback-on-close a HW fix Unfortunately it's too risky to enable by default all the time. So, we'll make it a hw fix, and hopefully one day can make it default on. Also makes save states readback the TC as well. --- bin/resources/GameIndex.yaml | 4 +++ pcsx2-qt/Settings/GraphicsSettingsWidget.cpp | 5 +++ pcsx2-qt/Settings/GraphicsSettingsWidget.ui | 33 ++++++++++++-------- pcsx2/Config.h | 1 + pcsx2/Docs/gamedb-schema.json | 5 +++ pcsx2/Frontend/FullscreenUI.cpp | 3 ++ pcsx2/Frontend/ImGuiOverlays.cpp | 2 ++ pcsx2/GS/GS.cpp | 9 ++++-- pcsx2/GS/GSState.cpp | 16 ++++++++++ pcsx2/GS/GSState.h | 4 ++- pcsx2/GS/Renderers/Common/GSRenderer.cpp | 9 ------ pcsx2/GS/Renderers/Common/GSRenderer.h | 3 -- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 8 +++-- pcsx2/GS/Renderers/HW/GSRendererHW.h | 1 + pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 15 ++++++--- pcsx2/GS/Renderers/HW/GSTextureCache.h | 3 +- pcsx2/GameDatabase.cpp | 8 +++++ pcsx2/GameDatabase.h | 1 + pcsx2/Pcsx2Config.cpp | 3 ++ 19 files changed, 96 insertions(+), 37 deletions(-) diff --git a/bin/resources/GameIndex.yaml b/bin/resources/GameIndex.yaml index d0c3c0c5c6..1694ffcfa2 100644 --- a/bin/resources/GameIndex.yaml +++ b/bin/resources/GameIndex.yaml @@ -12860,6 +12860,8 @@ SLES-51504: SLES-51507: name: "Futurama" region: "PAL-M5" + gsHWFixes: + readTCOnClose: 1 # Fixes render to target getting lost on state/switch. SLES-51508: name: "Hulk, The" region: "PAL-M5" @@ -42646,6 +42648,8 @@ SLUS-20439: name: "Futurama" region: "NTSC-U" compat: 5 + gsHWFixes: + readTCOnClose: 1 # Fixes render to target getting lost on state/switch. SLUS-20440: name: "Kya - Dark Lineage" region: "NTSC-U" diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index dacf3a408f..db1ec41003 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -198,6 +198,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* SettingWidgetBinder::BindWidgetToBoolSetting( sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false); ////////////////////////////////////////////////////////////////////////// // HW Upscaling Fixes @@ -537,6 +538,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* dialog->registerWidgetHelp(m_ui.textureInsideRt, tr("Texture Inside RT"), tr("Unchecked"), tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer. " "In some selected games this is enabled by default regardless of this setting.")); + + dialog->registerWidgetHelp(m_ui.readTCOnClose, tr("Read Targets When Closing"), tr("Unchecked"), + tr("Flushes all targets in the texture cache back to local memory when shutting down. Can prevent lost visuals when saving " + "state or switching renderers, but can also cause graphical corruption.")); } // Upscaling Fixes tab diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index d8249cb8bb..ead2e10fbf 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -947,13 +947,6 @@ - - - - Auto Flush - - - @@ -961,6 +954,13 @@ + + + + Auto Flush + + + @@ -968,10 +968,10 @@ - - + + - Disable Safe Features + Preload Frame Data @@ -982,10 +982,10 @@ - - + + - Preload Frame Data + Disable Safe Features @@ -996,6 +996,13 @@ + + + + Read Targets When Closing + + + diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 9d010785f6..9d7a3eb314 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -664,6 +664,7 @@ struct Pcsx2Config UserHacks_AlignSpriteX : 1, UserHacks_AutoFlush : 1, UserHacks_CPUFBConversion : 1, + UserHacks_ReadTCOnClose : 1, UserHacks_DisableDepthSupport : 1, UserHacks_DisablePartialInvalidation : 1, UserHacks_DisableSafeFeatures : 1, diff --git a/pcsx2/Docs/gamedb-schema.json b/pcsx2/Docs/gamedb-schema.json index 9946bdef0d..18c8a1357c 100644 --- a/pcsx2/Docs/gamedb-schema.json +++ b/pcsx2/Docs/gamedb-schema.json @@ -126,6 +126,11 @@ "minimum": 0, "maximum": 1 }, + "readTCOnClose": { + "type": "integer", + "minimum": 0, + "maximum": 1 + }, "disableDepthSupport": { "type": "integer", "minimum": 0, diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index d24647d1ef..881ea28be1 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -3196,6 +3196,9 @@ void FullscreenUI::DrawGraphicsSettingsPage() DrawToggleSetting(bsi, "Texture Inside Render Target", "Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer.", "EmuCore/GS", "UserHacks_TextureInsideRt", false, manual_hw_fixes); + DrawToggleSetting(bsi, "Read Targets When Closing", + "Flushes all targets in the texture cache back to local memory when shutting down.", "EmuCore/GS", + "UserHacks_ReadTCOnClose", false, manual_hw_fixes); MenuHeading("Upscaling Fixes"); DrawIntListSetting(bsi, "Half-Pixel Offset", "Adjusts vertices relative to upscaling.", "EmuCore/GS", diff --git a/pcsx2/Frontend/ImGuiOverlays.cpp b/pcsx2/Frontend/ImGuiOverlays.cpp index b710ba6314..2c077bdd0e 100644 --- a/pcsx2/Frontend/ImGuiOverlays.cpp +++ b/pcsx2/Frontend/ImGuiOverlays.cpp @@ -421,6 +421,8 @@ void ImGuiManager::DrawSettingsOverlay() APPEND("AF "); if (GSConfig.UserHacks_CPUFBConversion) APPEND("FBC "); + if (GSConfig.UserHacks_ReadTCOnClose) + APPEND("FTC "); if(GSConfig.UserHacks_DisableDepthSupport) APPEND("DDE "); if (GSConfig.UserHacks_DisablePartialInvalidation) diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 059b2dfa25..cdf4ed4d9b 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -252,6 +252,9 @@ bool GSreopen(bool recreate_display, bool recreate_renderer, const Pcsx2Config:: if (recreate_renderer) g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN); + if (GSConfig.UserHacks_ReadTCOnClose) + g_gs_renderer->ReadbackTextureCache(); + freezeData fd = {}; std::unique_ptr fd_data; if (recreate_renderer) @@ -273,8 +276,8 @@ bool GSreopen(bool recreate_display, bool recreate_renderer, const Pcsx2Config:: else { // Make sure nothing is left over. - g_gs_renderer->PurgePool(); g_gs_renderer->PurgeTextureCache(); + g_gs_renderer->PurgePool(); } if (recreate_display) @@ -762,6 +765,8 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) GSConfig.UserHacks_CPUCLUTRender != old_config.UserHacks_CPUCLUTRender || GSConfig.UserHacks_GPUTargetCLUTMode != old_config.UserHacks_GPUTargetCLUTMode) { + if (GSConfig.UserHacks_ReadTCOnClose) + g_gs_renderer->ReadbackTextureCache(); g_gs_renderer->PurgeTextureCache(); g_gs_renderer->PurgePool(); } @@ -800,8 +805,6 @@ void GSSwitchRenderer(GSRendererType new_renderer) if (existing_api == RenderAPI::OpenGLES) existing_api = RenderAPI::OpenGL; - g_gs_renderer->PurgeTextureCache(); - const bool is_software_switch = (new_renderer == GSRendererType::SW || GSConfig.Renderer == GSRendererType::SW); const bool recreate_display = (!is_software_switch && existing_api != GetAPIForRenderer(new_renderer)); const Pcsx2Config::GSOptions old_config(GSConfig); diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index d82ae80cd2..b243b41d6b 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -2126,6 +2126,19 @@ void GSState::ReadLocalMemoryUnsync(u8* mem, int qwc, GIFRegBITBLTBUF BITBLTBUF, m_mem.ReadImageX(tb.x, tb.y, mem, len, BITBLTBUF, TRXPOS, TRXREG); } +void GSState::PurgePool() +{ + g_gs_device->PurgePool(); +} + +void GSState::PurgeTextureCache() +{ +} + +void GSState::ReadbackTextureCache() +{ +} + template void GSState::Transfer<0>(const u8* mem, u32 size); template void GSState::Transfer<1>(const u8* mem, u32 size); template void GSState::Transfer<2>(const u8* mem, u32 size); @@ -2345,6 +2358,9 @@ int GSState::Freeze(freezeData* fd, bool sizeonly) Flush(GSFlushReason::SAVESTATE); + if (GSConfig.UserHacks_ReadTCOnClose) + ReadbackTextureCache(); + u8* data = fd->data; const u32 version = STATE_VERSION; diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index 3b7605bf8f..5ae2756da4 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -886,7 +886,9 @@ public: bool TestDrawChanged(); void FlushWrite(); virtual void Draw() = 0; - virtual void PurgePool() = 0; + virtual void PurgePool(); + virtual void PurgeTextureCache(); + virtual void ReadbackTextureCache(); virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool eewrite = false) {} virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false) {} virtual void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) {} diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 3d3647e899..c7a5c5128f 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -829,15 +829,6 @@ void GSRenderer::EndCapture() GSCapture::EndCapture(); } -void GSRenderer::PurgePool() -{ - g_gs_device->PurgePool(); -} - -void GSRenderer::PurgeTextureCache() -{ -} - GSTexture* GSRenderer::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, const GSVector2i& size) { return nullptr; diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.h b/pcsx2/GS/Renderers/Common/GSRenderer.h index fc504d2777..479843740c 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.h +++ b/pcsx2/GS/Renderers/Common/GSRenderer.h @@ -53,9 +53,6 @@ public: virtual GSVector2 GetTextureScaleFactor() { return { 1.0f, 1.0f }; } GSVector2i GetInternalResolution(); - virtual void PurgePool() override; - virtual void PurgeTextureCache(); - virtual GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, const GSVector2i& size); bool SaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders, diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 3b6b33c81a..f1001a3d16 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -71,8 +71,12 @@ void GSRendererHW::Destroy() void GSRendererHW::PurgeTextureCache() { - GSRenderer::PurgeTextureCache(); - m_tc->RemoveAll(true); + m_tc->RemoveAll(); +} + +void GSRendererHW::ReadbackTextureCache() +{ + m_tc->ReadbackAll(); } GSTexture* GSRendererHW::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, const GSVector2i& size) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index 4c6c8cf79e..07a5bc5087 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -166,6 +166,7 @@ public: void Draw() override; void PurgeTextureCache() override; + void ReadbackTextureCache() override; GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, const GSVector2i& size) override; // Called by the texture cache to know if current texture is useful diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index dc6ebe9939..b375d97499 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -46,18 +46,23 @@ GSTextureCache::~GSTextureCache() _aligned_free(s_unswizzle_buffer); } -void GSTextureCache::RemoveAll(bool readback_targets) +void GSTextureCache::ReadbackAll() +{ + for (int type = 0; type < 2; type++) + { + for (auto t : m_dst[type]) + Read(t, t->m_drawn_since_read); + } +} + +void GSTextureCache::RemoveAll() { m_src.RemoveAll(); for (int type = 0; type < 2; type++) { for (auto t : m_dst[type]) - { - if (readback_targets) - Read(t, t->m_drawn_since_read); delete t; - } m_dst[type].clear(); } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 19e89c7d7e..f3877bfde8 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -406,7 +406,8 @@ public: void Read(Target* t, const GSVector4i& r); void Read(Source* t, const GSVector4i& r); - void RemoveAll(bool readback_targets = false); + void RemoveAll(); + void ReadbackAll(); void AddDirtyRectTarget(Target* target, GSVector4i rect, u32 psm, u32 bw); GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, const GSVector2i& size); diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index 0fcc0d8786..15388622f9 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -342,6 +342,7 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml: static const char* s_gs_hw_fix_names[] = { "autoFlush", "cpuFramebufferConversion", + "readTCOnClose", "disableDepthSupport", "wrapGSMem", "preloadFrameData", @@ -548,6 +549,9 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti case GSHWFixId::CPUFramebufferConversion: return (static_cast(config.UserHacks_CPUFBConversion) == value); + case GSHWFixId::FlushTCOnClose: + return (static_cast(config.UserHacks_ReadTCOnClose) == value); + case GSHWFixId::DisableDepthSupport: return (static_cast(config.UserHacks_DisableDepthSupport) == value); @@ -654,6 +658,10 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions& config.UserHacks_CPUFBConversion = (value > 0); break; + case GSHWFixId::FlushTCOnClose: + config.UserHacks_ReadTCOnClose = (value > 0); + break; + case GSHWFixId::DisableDepthSupport: config.UserHacks_DisableDepthSupport = (value > 0); break; diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h index 2250609d54..340a82054b 100644 --- a/pcsx2/GameDatabase.h +++ b/pcsx2/GameDatabase.h @@ -62,6 +62,7 @@ namespace GameDatabaseSchema // boolean settings AutoFlush, CPUFramebufferConversion, + FlushTCOnClose, DisableDepthSupport, WrapGSMem, PreloadFrameData, diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 0b3794e076..62db4165cd 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -429,6 +429,7 @@ Pcsx2Config::GSOptions::GSOptions() UserHacks_AlignSpriteX = false; UserHacks_AutoFlush = false; UserHacks_CPUFBConversion = false; + UserHacks_ReadTCOnClose = false; UserHacks_DisableDepthSupport = false; UserHacks_DisablePartialInvalidation = false; UserHacks_DisableSafeFeatures = false; @@ -640,6 +641,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) GSSettingBoolEx(UserHacks_AlignSpriteX, "UserHacks_align_sprite_X"); GSSettingBoolEx(UserHacks_AutoFlush, "UserHacks_AutoFlush"); GSSettingBoolEx(UserHacks_CPUFBConversion, "UserHacks_CPU_FB_Conversion"); + GSSettingBoolEx(UserHacks_ReadTCOnClose, "UserHacks_ReadTCOnClose"); GSSettingBoolEx(UserHacks_DisableDepthSupport, "UserHacks_DisableDepthSupport"); GSSettingBoolEx(UserHacks_DisablePartialInvalidation, "UserHacks_DisablePartialInvalidation"); GSSettingBoolEx(UserHacks_DisableSafeFeatures, "UserHacks_Disable_Safe_Features"); @@ -770,6 +772,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks() UserHacks_DisablePartialInvalidation = false; UserHacks_DisableDepthSupport = false; UserHacks_CPUFBConversion = false; + UserHacks_ReadTCOnClose = false; UserHacks_TextureInsideRt = false; UserHacks_TCOffsetX = 0; UserHacks_TCOffsetY = 0;