From ebeb646e4d73ab331e9ab39b4cca2ef9d85eded0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 19 Mar 2023 22:24:29 +1000 Subject: [PATCH] GS/HW: Relax CPU sprite render requirements further via levels --- pcsx2-qt/Settings/GraphicsSettingsWidget.cpp | 23 ++- pcsx2-qt/Settings/GraphicsSettingsWidget.h | 1 + pcsx2-qt/Settings/GraphicsSettingsWidget.ui | 141 +++++++++++-------- pcsx2/Config.h | 3 +- pcsx2/Docs/gamedb-schema.json | 5 + pcsx2/Frontend/FullscreenUI.cpp | 4 + pcsx2/Frontend/ImGuiOverlays.cpp | 2 +- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 36 ++--- pcsx2/GameDatabase.cpp | 8 ++ pcsx2/GameDatabase.h | 1 + pcsx2/Pcsx2Config.cpp | 3 + 11 files changed, 142 insertions(+), 85 deletions(-) diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index 60d5d55306..ec42af854c 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -186,16 +186,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast(AccBlendLevel::Basic)); SettingWidgetBinder::BindWidgetToIntSetting( sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast(TexturePreloadingLevel::Off)); - connect(m_ui.trilinearFiltering, QOverload::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onTrilinearFilteringChanged); - connect(m_ui.gpuPaletteConversion, QOverload::of(&QCheckBox::stateChanged), this, - &GraphicsSettingsWidget::onGpuPaletteConversionChanged); - connect(m_ui.textureInsideRt, QOverload::of(&QComboBox::currentIndexChanged), this, - &GraphicsSettingsWidget::onTextureInsideRtChanged); onTrilinearFilteringChanged(); - onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState()); - onTextureInsideRtChanged(); ////////////////////////////////////////////////////////////////////////// // HW Renderer Fixes @@ -203,6 +196,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast(CRCHackLevel::Automatic), -1); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderBW, "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderLevel, "EmuCore/GS", "UserHacks_CPUSpriteRenderLevel", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuCLUTRender, "EmuCore/GS", "UserHacks_CPUCLUTRender", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuTargetCLUTMode, "EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0); @@ -220,6 +214,15 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.targetPartialInvalidation, "EmuCore/GS", "UserHacks_TargetPartialInvalidation", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false); + connect(m_ui.cpuSpriteRenderBW, QOverload::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onCPUSpriteRenderBWChanged); + connect(m_ui.textureInsideRt, QOverload::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onTextureInsideRtChanged); + connect(m_ui.gpuPaletteConversion, QOverload::of(&QCheckBox::stateChanged), this, + &GraphicsSettingsWidget::onGpuPaletteConversionChanged); + onCPUSpriteRenderBWChanged(); + onTextureInsideRtChanged(); + onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState()); ////////////////////////////////////////////////////////////////////////// // HW Upscaling Fixes @@ -889,6 +892,12 @@ void GraphicsSettingsWidget::onGpuPaletteConversionChanged(int state) m_ui.anisotropicFiltering->setDisabled(disabled); } +void GraphicsSettingsWidget::onCPUSpriteRenderBWChanged() +{ + const int value = m_dialog->getEffectiveIntValue("EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0); + m_ui.cpuSpriteRenderLevel->setEnabled(value != 0); +} + void GraphicsSettingsWidget::onTextureInsideRtChanged() { const bool disabled = static_cast(m_ui.textureInsideRt->currentIndex()) >= GSTextureInRtMode::InsideTargets; diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.h b/pcsx2-qt/Settings/GraphicsSettingsWidget.h index c3de1794b6..592827289c 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.h +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.h @@ -41,6 +41,7 @@ private Q_SLOTS: void onAdapterChanged(int index); void onTrilinearFilteringChanged(); void onGpuPaletteConversionChanged(int state); + void onCPUSpriteRenderBWChanged(); void onTextureInsideRtChanged(); void onFullscreenModeChanged(int index); void onShadeBoostChanged(); diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index b9f0247f89..e8c1679349 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -813,65 +813,6 @@ - - - - - 0 (Disabled) - - - - - 1 (64 Max Width) - - - - - 2 (128 Max Width) - - - - - 3 (192 Max Width) - - - - - 4 (256 Max Width) - - - - - 5 (320 Max Width) - - - - - 6 (384 Max Width) - - - - - 7 (448 Max Width) - - - - - 8 (512 Max Width) - - - - - 9 (576 Max Width) - - - - - 10 (640 Max Width) - - - - @@ -1096,6 +1037,88 @@ + + + + + + + 0 (Disabled) + + + + + 1 (64 Max Width) + + + + + 2 (128 Max Width) + + + + + 3 (192 Max Width) + + + + + 4 (256 Max Width) + + + + + 5 (320 Max Width) + + + + + 6 (384 Max Width) + + + + + 7 (448 Max Width) + + + + + 8 (512 Max Width) + + + + + 9 (576 Max Width) + + + + + 10 (640 Max Width) + + + + + + + + + Sprites Only + + + + + Sprites/Triangles + + + + + Blended Sprites/Triangles + + + + + + diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 1d0ebb8445..b6f4d11038 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -753,7 +753,8 @@ struct Pcsx2Config int UserHacks_TCOffsetX{0}; int UserHacks_TCOffsetY{0}; int UserHacks_CPUSpriteRenderBW{0}; - int UserHacks_CPUCLUTRender{ 0 }; + int UserHacks_CPUSpriteRenderLevel{0}; + int UserHacks_CPUCLUTRender{0}; GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode{GSGPUTargetCLUTMode::Disabled}; GSTextureInRtMode UserHacks_TextureInsideRt{GSTextureInRtMode::Disabled}; TriFiltering TriFilter{TriFiltering::Automatic}; diff --git a/pcsx2/Docs/gamedb-schema.json b/pcsx2/Docs/gamedb-schema.json index 8e153bb9e5..f18b980725 100644 --- a/pcsx2/Docs/gamedb-schema.json +++ b/pcsx2/Docs/gamedb-schema.json @@ -241,6 +241,11 @@ "minimum": 1, "maximum": 10 }, + "cpuSpriteRenderLevel": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, "cpuCLUTRender": { "type": "integer", "minimum": 1, diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index 90e088b416..aa354451cb 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -3170,6 +3170,8 @@ void FullscreenUI::DrawGraphicsSettingsPage() static constexpr const char* s_cpu_sprite_render_bw_options[] = {"0 (Disabled)", "1 (64 Max Width)", "2 (128 Max Width)", "3 (192 Max Width)", "4 (256 Max Width)", "5 (320 Max Width)", "6 (384 Max Width)", "7 (448 Max Width)", "8 (512 Max Width)", "9 (576 Max Width)", "10 (640 Max Width)"}; + static constexpr const char* s_cpu_sprite_render_level_options[] = { + "Sprites Only", "Sprites/Triangles", "Blended Sprites/Triangles"}; static constexpr const char* s_cpu_clut_render_options[] = {"0 (Disabled)", "1 (Normal)", "2 (Aggressive)"}; static constexpr const char* s_texture_inside_rt_options[] = {"Disabled", "Inside Target", "Merge Targets"}; static constexpr const char* s_half_pixel_offset_options[] = { @@ -3182,6 +3184,8 @@ void FullscreenUI::DrawGraphicsSettingsPage() "UserHacks_Half_Bottom_Override", -1, s_generic_options, std::size(s_generic_options), -1); DrawIntListSetting(bsi, "CPU Sprite Render Size", "Uses software renderer to draw texture decompression-like sprites.", "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0, s_cpu_sprite_render_bw_options, std::size(s_cpu_sprite_render_bw_options)); + DrawIntListSetting(bsi, "CPU Sprite Render Level", "Determines filter level for CPU sprite render.", "EmuCore/GS", + "UserHacks_CPUSpriteRenderLevel", 0, s_cpu_sprite_render_level_options, std::size(s_cpu_sprite_render_level_options)); DrawIntListSetting(bsi, "Software CLUT Render", "Uses software renderer to draw texture CLUT points/sprites.", "EmuCore/GS", "UserHacks_CPUCLUTRender", 0, s_cpu_clut_render_options, std::size(s_cpu_clut_render_options)); DrawIntSpinBoxSetting( diff --git a/pcsx2/Frontend/ImGuiOverlays.cpp b/pcsx2/Frontend/ImGuiOverlays.cpp index 115ff5957b..89c06dab99 100644 --- a/pcsx2/Frontend/ImGuiOverlays.cpp +++ b/pcsx2/Frontend/ImGuiOverlays.cpp @@ -404,7 +404,7 @@ void ImGuiManager::DrawSettingsOverlay() if (GSConfig.UserHacks_TCOffsetX != 0 || GSConfig.UserHacks_TCOffsetY != 0) APPEND("TCO={}/{} ", GSConfig.UserHacks_TCOffsetX, GSConfig.UserHacks_TCOffsetY); if (GSConfig.UserHacks_CPUSpriteRenderBW != 0) - APPEND("CSBW={} ", GSConfig.UserHacks_CPUSpriteRenderBW); + APPEND("CSBW={}/{} ", GSConfig.UserHacks_CPUSpriteRenderBW, GSConfig.UserHacks_CPUSpriteRenderLevel); if (GSConfig.UserHacks_CPUCLUTRender != 0) APPEND("CCLUT={} ", GSConfig.UserHacks_CPUCLUTRender); if (GSConfig.UserHacks_GPUTargetCLUTMode != GSGPUTargetCLUTMode::Disabled) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 6e2dee6c5d..fa70d459a4 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -4568,40 +4568,42 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDrawAggressive() bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_tex) { // Master enable. - if (GSConfig.UserHacks_CPUSpriteRenderBW == 0) + const int bw = GSConfig.UserHacks_CPUSpriteRenderBW; + const int level = GSConfig.UserHacks_CPUSpriteRenderLevel; + if (bw == 0) return false; // We don't ever want to do this when we have a depth buffer, and only for textured sprites. - if (no_rt || !no_ds || !draw_sprite_tex) + if (no_rt || !no_ds || (level == 0 && !draw_sprite_tex)) return false; // Check the size threshold. Spider-man 2 uses a FBW of 32 for some silly reason... - if (m_context->FRAME.FBW > static_cast(GSConfig.UserHacks_CPUSpriteRenderBW) && m_context->FRAME.FBW != 32) + if (m_context->FRAME.FBW > static_cast(bw) && m_context->FRAME.FBW != 32) return false; // We shouldn't be using mipmapping, and this shouldn't be a blended draw. - // TODO: Jak 3 builds textures semi-procedurally using blending, and would be a good candidate here. - if (IsMipMapActive() || !IsOpaque()) + if (level < 2 && (IsMipMapActive() || !IsOpaque())) return false; // Make sure this isn't something we've actually rendered to (e.g. a texture shuffle). - // We do this by checking the texture block width against the target's block width, as all the decompression draws - // will use a much smaller block size than the framebuffer. - GSTextureCache::Target* src_target = m_tc->GetTargetWithSharedBits(m_context->TEX0.TBP0, m_context->TEX0.PSM); - if (src_target && src_target->m_TEX0.TBW == m_context->TEX0.TBW) + if (PRIM->TME) { - // If the EE has written over our sample area, we're fine to do this on the CPU, despite the target. - if (!src_target->m_dirty.empty()) + GSTextureCache::Target* src_target = m_tc->GetTargetWithSharedBits(m_context->TEX0.TBP0, m_context->TEX0.PSM); + if (src_target) { - const GSVector4i tr(GetTextureMinMax(m_context->TEX0, m_context->CLAMP, m_vt.IsLinear()).coverage); - for (GSDirtyRect& rc : src_target->m_dirty) + // If the EE has written over our sample area, we're fine to do this on the CPU, despite the target. + if (!src_target->m_dirty.empty()) { - if (!rc.GetDirtyRect(m_context->TEX0).rintersect(tr).rempty()) - return true; + const GSVector4i tr(GetTextureMinMax(m_context->TEX0, m_context->CLAMP, m_vt.IsLinear()).coverage); + for (GSDirtyRect& rc : src_target->m_dirty) + { + if (!rc.GetDirtyRect(m_context->TEX0).rintersect(tr).rempty()) + return true; + } } - } - return false; + return false; + } } // We can use the sw prim render path! diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index ba083a8fed..9f38cf75de 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -366,6 +366,7 @@ static const char* s_gs_hw_fix_names[] = { "texturePreloading", "deinterlace", "cpuSpriteRenderBW", + "cpuSpriteRenderLevel", "cpuCLUTRender", "gpuTargetCLUT", "gpuPaletteConversion", @@ -631,6 +632,9 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti case GSHWFixId::CPUSpriteRenderBW: return (config.UserHacks_CPUSpriteRenderBW == value); + case GSHWFixId::CPUSpriteRenderLevel: + return (config.UserHacks_CPUSpriteRenderLevel == value); + case GSHWFixId::CPUCLUTRender: return (config.UserHacks_CPUCLUTRender == value); @@ -814,6 +818,10 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions& config.UserHacks_CPUSpriteRenderBW = value; break; + case GSHWFixId::CPUSpriteRenderLevel: + config.UserHacks_CPUSpriteRenderLevel = value; + break; + case GSHWFixId::CPUCLUTRender: config.UserHacks_CPUCLUTRender = value; break; diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h index fb15cfc984..33f27ac66a 100644 --- a/pcsx2/GameDatabase.h +++ b/pcsx2/GameDatabase.h @@ -87,6 +87,7 @@ namespace GameDatabaseSchema TexturePreloading, Deinterlace, CPUSpriteRenderBW, + CPUSpriteRenderLevel, CPUCLUTRender, GPUTargetCLUT, GPUPaletteConversion, diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 56b081daf6..6894c491b4 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -524,6 +524,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const OpEqu(UserHacks_TCOffsetX) && OpEqu(UserHacks_TCOffsetY) && OpEqu(UserHacks_CPUSpriteRenderBW) && + OpEqu(UserHacks_CPUSpriteRenderLevel) && OpEqu(UserHacks_CPUCLUTRender) && OpEqu(UserHacks_GPUTargetCLUTMode) && OpEqu(UserHacks_TextureInsideRt) && @@ -717,6 +718,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) GSSettingIntEx(UserHacks_TCOffsetX, "UserHacks_TCOffsetX"); GSSettingIntEx(UserHacks_TCOffsetY, "UserHacks_TCOffsetY"); GSSettingIntEx(UserHacks_CPUSpriteRenderBW, "UserHacks_CPUSpriteRenderBW"); + GSSettingIntEx(UserHacks_CPUSpriteRenderLevel, "UserHacks_CPUSpriteRenderLevel"); GSSettingIntEx(UserHacks_CPUCLUTRender, "UserHacks_CPUCLUTRender"); GSSettingIntEnumEx(UserHacks_GPUTargetCLUTMode, "UserHacks_GPUTargetCLUTMode"); GSSettingIntEnumEx(TriFilter, "TriFilter"); @@ -792,6 +794,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks() UserHacks_TCOffsetX = 0; UserHacks_TCOffsetY = 0; UserHacks_CPUSpriteRenderBW = 0; + UserHacks_CPUSpriteRenderLevel = 0; UserHacks_CPUCLUTRender = 0; UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled; SkipDrawStart = 0;